Dokumentasi API DripPay
Integrasikan pembuatan pembayaran QRIS dinamis, periksa status transaksi, cocokkan notifikasi pembayaran Android secara real-time, dan terima peristiwa webhook yang ditandatangani secara kriptografis.
Memulai
DripPay mengoordinasikan status dan verifikasi pembayaran, sementara dana mengalir langsung ke rekening bank/dompet QRIS merchant.
Daftarkan merchant
Unggah QRIS statis untuk mendeteksi NMID. Tanpa berbagi, ID merchant memakai NMID; saat berbagi diaktifkan, DripPay membuat ID merchant terpisah untuk tiap merchant.
Buat kunci
Buat kunci API (dp_live_...) untuk backend Anda dan kunci perangkat (dv_...) untuk penerus Android.
Listener & webhook
Atur penerusan notifikasi melalui listener Android. Terima peristiwa webhook payment.success yang ditandatangani secara instan.
Kirim kredensial Anda melalui header HTTP Authorization standar. DripPay menampilkan token teks biasa satu kali dan hanya menyimpan hash SHA-256-nya.
Jenis Kredensial | Awalan | Cakupan & Tujuan Penggunaan |
|---|---|---|
| Kunci API | dp_live_ | Penggunaan di server backend: membuat transaksi QRIS dinamis dan memeriksa status transaksi. |
| Kunci Perangkat | dv_ | Listener Android dengan cakupan merchant: meneruskan notifikasi pembayaran khusus untuk satu merchant. |
Authorization: Bearer dp_live_0123456789abcdef0123456789abcdef
Content-Type: application/jsonJaga kerahasiaan kunci API Anda. Jangan pernah memasukkannya ke kontrol versi atau menampilkannya dalam kode sisi klien. Segera cabut kunci yang telah disusupi melalui dasbor.
Membuat payload QRIS dinamis dari QRIS statis merchant Anda (berlaku selama 15 menit). DripPay otomatis menambahkan kode nominal unik (Rp1–Rp999) untuk memastikan pembayaran dapat diidentifikasi.
/api/v1/transactionsHeader Permintaan
Header | Nilai yang Diharapkan | Wajib |
|---|---|---|
Authorization | Bearer dp_live_... | Wajib |
Content-Type | application/json | Wajib |
Payload (Isi Permintaan)
Kolom | Tipe | Wajib | Deskripsi |
|---|---|---|---|
merchant_id | String | Wajib | ID bisnis merchant pada dasbor. Saat berbagi QRIS aktif, nominal unik dicadangkan bersama untuk merchant dengan NMID yang sama. |
amount | Integer | Wajib | Nominal dasar dalam Rupiah utuh (misalnya 25000). Harus > 0. |
curl -X POST "$DRIPPAY_BASE_URL/api/v1/transactions" \
-H "Authorization: Bearer $DRIPPAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"merchant_id":"ID2026MERCHANT001","amount":25000}'Respons Berhasil
201 CreatedTampilkan data.amount (nominal dasar + kode unik) kepada pelanggan dan tampilkan data.qris_dynamic sebagai gambar kode QR.
{
"success": true,
"message": "Transaction created",
"data": {
"transaction_id": "5fc90a06-bc10-4bd6-a226-1975e8cdaf71",
"reference": "cd87f732-27a3-4963-bbb4-6ad9aaeb0058",
"status": "pending",
"base_amount": 25000,
"unique_code": 961,
"amount": 25961,
"qris_dynamic": "00020101021226610014COM.GO-JEK.WWW01189360091430310651660210G0310651660303UMI51440014ID.CO.QRIS.WWW0215ID10254614875770303UMI5204899953033605405259615802ID5925ARIEF RACHMANSYAH, S.KOM,6010BALIKPAPAN61057612162070703A0163049E74",
"expires_at": "2026-10-11T12:40:00.000Z",
"paid_at": null,
"created_at": "2026-10-11T12:25:00.000Z",
"timezone": "Asia/Jakarta"
}
}Kesalahan
4xx / 5xxStatus HTTP | Kode kesalahan / alasan | Deskripsi |
|---|---|---|
401 | UNAUTHORIZED | Kunci API tidak ada, tidak valid, atau telah dicabut. |
404 | NOT_FOUND | ID merchant tidak ditemukan atau tidak aktif. |
409 | PAYMENT_AMOUNT_CONFLICT | Saat ini ada transaksi berstatus pending dengan nominal yang sama. Coba lagi. |
422 | VALIDATION_ERROR | merchant_id tidak valid, tidak ditemukan pada akun Anda, atau amount bukan nilai positif. |
{
"success": false,
"message": "A pending transaction already uses this amount. Retry the request.",
"code": "PAYMENT_AMOUNT_CONFLICT"
}Periksa dari backend Anda atau verifikasi status transaksi. Mengembalikan status terkini (pending, paid, atau expired).
/api/v1/transactions/:idHeader Permintaan
Header | Nilai yang Diharapkan | Wajib |
|---|---|---|
Authorization | Bearer dp_live_... | Wajib |
Parameter Jalur
Parameter | Tipe | Wajib | Deskripsi |
|---|---|---|---|
:id | UUID | Wajib | UUID transaksi yang dikembalikan saat transaksi dibuat. |
curl "$DRIPPAY_BASE_URL/api/v1/transactions/5fc90a06-bc10-4bd6-a226-1975e8cdaf71" \
-H "Authorization: Bearer $DRIPPAY_API_KEY"Respons Berhasil
200 OK{
"success": true,
"message": "Transaction retrieved",
"data": {
"transaction_id": "5fc90a06-bc10-4bd6-a226-1975e8cdaf71",
"reference": "cd87f732-27a3-4963-bbb4-6ad9aaeb0058",
"status": "paid",
"base_amount": 25000,
"unique_code": 961,
"amount": 25961,
"expires_at": "2026-10-11T12:40:00.000Z",
"paid_at": "2026-10-11T12:25:30.000Z",
"created_at": "2026-10-11T12:25:00.000Z",
"timezone": "Asia/Jakarta"
}
}Kesalahan
4xxStatus HTTP | Makna |
|---|---|
401 | Kunci API tidak ada atau tidak valid. |
404 | Transaksi tidak ditemukan atau bukan milik pengguna kunci API tersebut. |
{
"success": false,
"message": "Transaction not found"
}Menerima notifikasi push yang diteruskan dari aplikasi bank atau dompet digital. Mencocokkan nominal pembayaran dengan transaksi pending aktif milik merchant terkait.
/api/listenerHeader Permintaan
Header | Nilai | Wajib |
|---|---|---|
Authorization | Bearer dv_... | Wajib |
Content-Type | application/json | Wajib |
Payload (Isi Permintaan)
Kolom | Tipe | Wajib | Catatan |
|---|---|---|---|
text | String | Wajib | Teks notifikasi lengkap yang berisi nominal pembayaran (misalnya "Pembayaran QRIS Rp25.961..."). |
app | String | Opsional | Nama paket Android (misalnya com.gojek.app, id.co.bri.brimo). |
notification_id | String | Opsional | ID unik dari aplikasi penerus yang digunakan untuk deduplikasi kriptografis. |
curl -X POST "$DRIPPAY_BASE_URL/api/listener" \
-H "Authorization: Bearer $DRIPPAY_DEVICE_KEY" \
-H "Content-Type: application/json" \
-d '{"text":"Pembayaran QRIS Rp25.961 dari Budi Santoso berhasil diterima","app":"com.gojek.app","notification_id":"notif-1001"}'Respons
200 OK1. Transaksi Berhasil Dicocokkan
{
"success": true,
"message": "Payment notification matched",
"data": {
"matched": true,
"transaction_id": "5fc90a06-bc10-4bd6-a226-1975e8cdaf71",
"amount": 25961,
"payer_name": "Budi Santoso",
"bank_reference": null
}
}2. Notifikasi Duplikat atau Tidak Cocok
{
"success": true,
"message": "Notification was already processed",
"data": {
"matched": false,
"reason": "duplicate_notification"
}
}Kesalahan
4xxStatus HTTP | Makna |
|---|---|
401 | Kunci perangkat tidak valid atau telah dicabut. |
422 | Parameter text tidak ada di isi permintaan. |
{
"success": false,
"message": "Validation failed",
"errors": {
"text": "Notification text is required"
}
}DripPay mengirim peristiwa HTTPS POST ke URL webhook merchant yang dikonfigurasi setiap kali status transaksi berubah, termasuk saat Anda menandai transaksi pending sebagai paid secara manual dari halaman Transaksi.
Header Webhook
Header | Deskripsi |
|---|---|
X-DripPay-Event | Jenis peristiwa: payment.success, payment.expired, atau webhook.test. |
X-DripPay-Delivery | UUID pengiriman unik untuk deduplikasi dan pelacakan. |
X-DripPay-Signature | Tanda tangan HMAC SHA-256 berformat sha256=<hex>, dihitung dari isi mentah menggunakan rahasia webhook Anda. |
Payload Peristiwa
payment.success
{
"id": "08b8cd23426b145421291eeea56990a6",
"event": "payment.success",
"created_at": "2026-10-11T12:26:02.052Z",
"data": {
"transaction_id": "5fc90a06-bc10-4bd6-a226-1975e8cdaf71",
"reference": "cd87f732-27a3-4963-bbb4-6ad9aaeb0058",
"merchant_id": "ID2026MERCHANT001",
"merchant_name": "ARIEF RACHMANSYAH, S.KOM,",
"base_amount": 25000,
"unique_code": 961,
"amount": 25961,
"status": "paid",
"expires_at": "2026-10-11T12:40:00.000Z",
"paid_at": "2026-10-11T12:25:30.000Z"
}
}Verifikasi Tanda Tangan HMAC
Selalu verifikasi tanda tangan terhadap payload permintaan mentah yang belum diurai menggunakan perbandingan waktu konstan untuk mencegah serangan timing.
import { createHmac, timingSafeEqual } from 'node:crypto';
function verifyWebhook(rawBody, signatureHeader, secret) {
const expected = 'sha256=' + createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
const expectedBytes = Buffer.from(expected);
const receivedBytes = Buffer.from(signatureHeader ?? '');
return expectedBytes.length === receivedBytes.length
&& timingSafeEqual(expectedBytes, receivedBytes);
}Kebijakan Pengakuan & Percobaan Ulang
Webhook endpoints must return HTTP 2xx. Each request times out after 10 seconds. Failed callbacks are retried for up to 10 total attempts, including the initial send. Retry delays start at 30 seconds and double after each failure.
Each attempt records the request payload, HTTP status and response body, error, and duration. Response bodies are limited to 16 KiB. View attempts or resend a callback from the transaction list; resending starts a new delivery cycle without changing the transaction status.
Mengirim peristiwa uji untuk memverifikasi bahwa URL tujuan dan rahasia webhook Anda telah dikonfigurasi dengan benar dan menerima permintaan bertanda tangan.
/merchants/:id/webhook-testPayload (Isi Permintaan)
Kolom | Tipe | Wajib | Deskripsi |
|---|---|---|---|
webhook_url | String | Opsional | URL HTTPS publik untuk diuji (secara default menggunakan URL webhook merchant yang tersimpan). |
webhook_secret | String | Opsional | Rahasia penandatanganan HMAC (secara default menggunakan rahasia merchant yang tersimpan). |
curl -X POST "$DRIPPAY_BASE_URL/merchants/2c4cfd13-9a0f-4dee-95d0-735e8c35446a/webhook-test" \
-H "Cookie: auth_id=$SESSION_COOKIE" \
-H "Content-Type: application/json" \
-d '{"webhook_url":"https://your-domain.com/webhook","webhook_secret":"admin123"}'Respons Berhasil
200 OK{
"success": true,
"message": "Test webhook delivered",
"data": {
"status_code": 200,
"merchant": {
"id": "2c4cfd13-9a0f-4dee-95d0-735e8c35446a",
"name": "ARIEF RACHMANSYAH, S.KOM,",
"webhook_url": "https://your-domain.com/webhook",
"webhook_secret": "admin123"
}
}
}Kesalahan
4xx / 502Status HTTP | Kode kesalahan | Deskripsi |
|---|---|---|
422 | WEBHOOK_URL_REQUIRED | URL webhook belum dikonfigurasi atau dicantumkan dalam isi permintaan. |
502 | WEBHOOK_DELIVERY_FAILED | Server tujuan mengembalikan status non-2xx, mengalami timeout, atau menolak permintaan. |
{
"success": false,
"message": "Webhook test failed. Use a public HTTPS URL that responds with a 2xx status.",
"code": "WEBHOOK_DELIVERY_FAILED"
}DripPay mengembalikan struktur JSON standar dengan pesan deskriptif dan kode kesalahan terstruktur setiap kali panggilan API gagal.
Status | Nama Status | Makna & Penanganan yang Disarankan |
|---|---|---|
| 400 | Permintaan tidak valid (Bad Request) | Payload JSON tidak valid atau sintaks permintaan keliru. |
| 401 | Tidak terautentikasi (Unauthorized) | Kunci API dp_live_ atau kunci perangkat dv_ tidak ada atau tidak valid. |
| 404 | Tidak ditemukan (Not Found) | Sumber daya tidak ditemukan atau merupakan milik akun lain. |
| 409 | Konflik (Conflict) | PAYMENT_AMOUNT_CONFLICT: Nominal bertabrakan dengan transaksi berstatus pending yang masih aktif. Coba ulang secara otomatis. |
| 422 | Data tidak dapat diproses (Unprocessable Entity) | Validasi gagal. Periksa tipe kolom dan ketentuan kolom wajib. |
| 429 | Terlalu banyak permintaan (Too Many Requests) | Batas permintaan tercapai (60 permintaan per menit untuk API Transaksi, 120 permintaan per menit untuk listener Android). |
| 500 | Kesalahan server internal (Internal Server Error) | Terjadi kegagalan server yang tidak terduga. Silakan coba lagi dengan jeda eksponensial. |
{
"success": false,
"message": "Penjelasan singkat tentang kesalahan",
"code": "ERROR_CONSTANT_CODE",
"errors": {
"field_name": "Rincian validasi untuk kolom ini jika ada"
}
}
