Dokumentasi
Rest API v1
Integrasi Gopay Merchant dan Shopee Partner lewat satu API yang konsisten. Semua endpoint menerima dan mengembalikan JSON.
https://pay.odzreshop.id/api/v1
Quickstart
- 1.Daftar akun lalu masuk ke dashboard.
- 2.Buka menu Proyek → buat proyek baru (nama, QRIS, merchant).
- 3.Salin API key yang muncul sekali saja.
- 4.Panggil endpoint dengan header
X-API-Key.
Contoh panggilan pertama (cURL)
curl -X POST https://pay.odzreshop.id/api/v1/transaction/create \
-H "X-API-Key: odzre_live_xxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"amount": 25000,
"customerName": "Budi Santoso",
"description": "Pembayaran pesanan #1234"
}'
Autentikasi
Semua endpoint memerlukan API key. Sertakan pada salah satu dari:
Header (disarankan)
X-API-Key: odzre_live_xxx
Bearer token
Authorization: Bearer odzre_live_xxx
API key hanya tampil satu kali saat dibuat. Simpan di variabel lingkungan server — jangan pernah di kode frontend atau repositori.
Rate Limit & Langganan
Akses API memerlukan langganan aktif (paket di menu Tagihan dashboard). Batas permintaan per menit mengikuti paket Anda — total request tidak dibatasi. Setiap response menyertakan header:
X-RateLimit-Limit: 60 # sesuai paket Anda X-RateLimit-Remaining: 57 Retry-After: 14 # hanya saat terkena limit (HTTP 429)
Saat langganan kedaluwarsa, semua request API ditolak dengan 403 SUBSCRIPTION_REQUIRED — proyek dan API key tetap utuh, langsung aktif kembali setelah diperpanjang.
/api/v1/profile
Mengembalikan informasi akun dan proyek pemilik API key.
Contoh — JavaScript (fetch)
const res = await fetch('https://pay.odzreshop.id/api/v1/profile', {
headers: { 'X-API-Key': process.env.ODZRE_API_KEY },
});
const json = await res.json();
console.log(json.data.project.name);
Response 200
{
"success": true,
"data": {
"user": {
"id": "uuid",
"email": "john.doe@example.com",
"full_name": "John Doe",
"company": "Doe Digital",
"created_at": "2026-01-15T08:00:00.000Z"
},
"project": {
"id": "uuid",
"name": "Toko Sepatu Online",
"merchant": "gopay"
},
"scopes": ["profile:read", "transaction:write", "transaction:read"]
},
"timestamp": "2026-09-13T03:00:00.000Z"
}
/api/v1/transaction/create
Membuat transaksi QRIS baru. Status awal pending.
Parameter body
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
amount | integer | Ya | Nominal dalam rupiah (100 – 50.000.000) |
orderId | string | Tidak | ID pesanan Anda (4-64 char). Kosong = dibuat otomatis |
customerName | string | Tidak | Nama pelanggan |
customerEmail | string | Tidak | Email pelanggan |
customerPhone | string | Tidak | Nomor telepon pelanggan |
description | string | Tidak | Keterangan transaksi (maks. 200 char) |
expiryMinutes | integer | Tidak | Masa berlaku (5–1440 menit, default 30) |
callbackUrl | string | Tidak | URL webhook saat status berubah — lihat Webhooks |
Contoh — PHP (cURL)
<?php
$ch = curl_init('https://pay.odzreshop.id/api/v1/transaction/create');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'X-API-Key: ' . getenv('ODZRE_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode(['amount' => 25000]),
]);
$res = json_decode(curl_exec($ch), true);
echo $res['data']['qris_string'];
Response 201
{
"success": true,
"data": {
"order_id": "ODZ-260913-K3P6W6CHKM",
"status": "pending",
"merchant": "shopee",
"requested_amount": 25000,
"unique_code": 137,
"amount": 25137,
"fee": 0,
"qris_string": "00020101021126...",
"customer": { "name": "Budi Santoso", "email": null, "phone": null },
"description": "Pembayaran pesanan #1234",
"provider_transaction_id": null,
"paid_at": null,
"expires_at": "2026-09-13T03:30:00.000Z",
"created_at": "2026-09-13T03:00:00.000Z"
},
"timestamp": "2026-09-13T03:00:00.000Z"
}
Nominal final amount = requested_amount + unique_code (Rp 1–999, agar transaksi nominal sama tidak tertukar).
Tampilkan qris_string sebagai QR code di aplikasi Anda — pembayaran terdeteksi otomatis ≤10 detik.
/api/v1/transaction/status/:orderId
Memeriksa status transaksi. Endpoint ini membaca status terbaru dari database —
worker kami mengecek pembayaran ke merchant setiap 10 detik, sehingga
perubahan status (mis. paid) tersedia otomatis tanpa perlu polling dari sisi Anda.
Contoh
curl -H "X-API-Key: odzre_live_xxx" \ https://pay.odzreshop.id/api/v1/transaction/status/ODZ-260913-K3P6W6CHKM
Nilai status yang mungkin
Webhooks
Saat pembayaran terdeteksi, sistem mengirim notifikasi otomatis (webhook) ke URL Anda berisi detail transaksi — sehingga aplikasi Anda tidak perlu polling berkala.
1. Cara Mengatur Webhook
Ada dua cara menentukan tujuan webhook — bisa dipakai salah satu atau keduanya
(jika keduanya terisi, callbackUrl per-transaksi yang dipakai):
- Per proyek — isi field Webhook URL di halaman detail proyek. Berlaku untuk semua transaksi proyek tersebut.
- Per transaksi — sertakan parameter
callbackUrlsaat memanggilPOST /transaction/create.
2. Kapan Webhook Terkirim
Event transaction.paid dikirim tepat setelah pembayaran
terverifikasi (deteksi mutasi berjalan tiap 10 detik, jadi
webhook tiba maksimal ±10 detik setelah pelanggan membayar). Sistem kirim
POST dengan body JSON:
POST https://app-anda.com/webhook
Content-Type: application/json
X-Odzre-Event: transaction.paid
X-Odzre-Signature: 5f8a3c...hexdigest
User-Agent: ODZRESHOP-Webhook/1.0
{
"event": "transaction.paid",
"order_id": "ORD-7K2M9XQ4",
"status": "paid",
"merchant": "gopay",
"requested_amount": 100000,
"unique_code": 57,
"amount": 100057,
"provider_transaction_id": "GP-TRX-88291037",
"paid_at": "2026-09-26T08:15:33.120Z",
"expires_at": "2026-09-26T09:00:00.000Z",
"created_at": "2026-09-26T08:02:11.004Z",
"timestamp": "2026-09-26T08:15:34.002Z"
}| Field | Tipe | Deskripsi |
|---|---|---|
event | string | Selalu transaction.paid |
order_id | string | ID transaksi Anda — kunci untuk mencocokkan order di sisi Anda |
status | string | paid |
merchant | string | Kanal pembayaran: gopay atau shopee |
requested_amount | number | Nominal asli sebelum kode unik |
unique_code | number | Kode unik yang ditambahkan |
amount | number | Nominal final yang dibayar (= requested + unique_code) |
provider_transaction_id | string | null | ID referensi dari Shopee/GoPay |
paid_at | string | null | Waktu pembayaran (ISO 8601 UTC) |
expires_at | string | Batas waktu bayar order |
created_at | string | Waktu order dibuat |
timestamp | string | Waktu webhook dibuat |
3. Verifikasi Signature
Setiap webhook di-sign dengan HMAC-SHA256 atas
raw body JSON, pada header X-Odzre-Signature.
Kunci yang dipakai adalah SESSION_SECRET server
(hubungi admin untuk mendapatkannya — bagikan hanya lewat kanal aman).
Selalu verifikasi sebelum memproses, dan bandingkan dengan perbandingan aman.
// Node.js (Express)
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const expected = crypto
.createHmac('sha256', SESSION_SECRET)
.update(req.body) // raw Buffer — JANGAN re-serialize
.digest('hex');
const received = req.headers['x-odzre-signature'] || '';
const ok = expected.length === received.length &&
crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(received));
if (!ok) return res.status(401).end();
const payload = JSON.parse(req.body.toString());
if (payload.event === 'transaction.paid') {
// tandai order payload.order_id sebagai LUNAS di database Anda
}
res.status(200).end();
});<?php // PHP
$raw = file_get_contents('php://input'); // raw body persis
$expected = hash_hmac('sha256', $raw, $SESSION_SECRET);
$received = $_SERVER['HTTP_X_ODZRE_SIGNATURE'] ?? '';
if (!hash_equals($expected, $received)) {
http_response_code(401); exit;
}
$payload = json_decode($raw, true);
if ($payload['event'] === 'transaction.paid') {
// tandai order $payload['order_id'] sebagai LUNAS
}
http_response_code(200);4. Aturan Retry
- Endpoint harus membalas status 2xx dalam 10 detik — proses berat sebaiknya dilakukan setelah merespons (queue).
- Gagal jaringan / HTTP ≥ 500 → dicoba ulang otomatis, maksimal 3 percobaan.
- Respons 4xx (termasuk 401/404) dianggap gagal final — tidak di-retry.
5. Batasan & Keamanan
- Hanya
http/httpsdengan hostname yang mengarah ke IP publik — localhost/private network ditolak otomatis. - Redirect tidak diikuti — pastikan URL endpoint langsung menjawab.
- Webhook dikirim dari server kami; untuk keamanan, validasi signature (bagian 3) — jangan hanya mengandalkan URL rahasia.
Kode Error
Semua error mengikuti format yang sama:
{
"success": false,
"error": {
"code": "INVALID_API_KEY",
"message": "API key tidak valid, sudah dicabut, atau proyeknya tidak aktif."
},
"timestamp": "2026-09-13T03:00:00.000Z"
}
| HTTP | Code | Arti |
|---|---|---|
| 401 | MISSING_API_KEY | Header X-API-Key tidak disertakan |
| 401 | MALFORMED_API_KEY | Format key salah |
| 401 | INVALID_API_KEY | Key tidak terdaftar / dicabut |
| 403 | INSUFFICIENT_SCOPE | Key tidak punya izin endpoint |
| 404 | NOT_FOUND | Transaksi tidak ditemukan |
| 409 | DUPLICATE_ORDER_ID | orderId sudah pernah dipakai |
| 409 | MERCHANT_NOT_CONNECTED | Proyek merchant belum terhubung / perlu sambung ulang |
| 403 | SUBSCRIPTION_REQUIRED | Langganan tidak aktif / kedaluwarsa — perpanjang di dashboard |
| 403 | PROJECT_LIMIT_REACHED | Batas jumlah proyek paket tercapai |
| 422 | VALIDATION_ERROR | Parameter tidak valid |
| 429 | RATE_LIMIT_EXCEEDED | Batas permintaan terlampaui |
| 502 | PROVIDER_ERROR | Provider menolak permintaan |
| 503 | UNIQUE_AMOUNT_UNAVAILABLE | Semua variasi nominal unik sedang terpakai |
| 500 | INTERNAL_ERROR | Kesalahan internal server |
Siap Mencoba?
Buat akun gratis dan dapatkan API key dalam waktu kurang dari lima menit.