Getting Started

DompetPay Merchant API memungkinkan Anda menerima pembayaran QRIS langsung dari website, bot Telegram/Discord, atau aplikasi Anda sendiri — tanpa pernah menyentuh alamat server backend kami secara langsung.

1Login / daftar akun merchant di dompetpay.biz.id
2Generate API Key dari Settings → Integrasi API
3Copy API Key (hanya ditampilkan sekali!)
4Atur Callback URL (redirect setelah user bayar)
5Atur Webhook URL (notifikasi server-to-server)
6Buat QRIS pertama Anda lewat endpoint Create Payment
7Terima Webhook saat user membayar
8Update status transaksi di sistem Anda sendiri
⚠️ Semua contoh kode di halaman ini memakai https://dompetpay.biz.id/api/v1 — domain WEB kami, BUKAN alamat server backend. Jangan pernah panggil alamat backend (IP/port) secara langsung dari aplikasi Anda; base URL publik ini yang wajib dipakai, dan tetap sama walau backend kami berpindah server kapan pun.

Authentication

Ada dua cara autentikasi tergantung endpoint yang dipanggil:

TipeHeaderDipakai untuk
API KeyX-API-Key: dpay_live_xxxEndpoint pembayaran (QRIS, cek status) — dipanggil dari server/bot Anda
Bearer TokenAuthorization: Bearer <access_token>Endpoint akun (kelola API Key, profil) — dipanggil setelah merchant login

Contoh header lengkap untuk memanggil endpoint pembayaran:

API Key

API Key adalah kredensial utama untuk endpoint pembayaran — perlakukan seperti password: jangan taruh di kode frontend/client, jangan commit ke git publik.

Buat API Key baru

POST /merchant/api-keys

Daftar API Key

GET /merchant/api-keys

Cabut API Key

DELETE /merchant/api-keys/{id}

Base URL

Semua endpoint Merchant API memakai satu base URL publik ini:

https://dompetpay.biz.id/api/v1

Backend kami boleh berjalan di server mana pun, port berapa pun (Node.js/NestJS) — merchant TIDAK PERNAH memanggilnya langsung. Semua request selalu lewat domain publik ini, yang diteruskan (reverse proxy) ke backend asli secara server-to-server. Ini praktik umum yang sama dipakai Stripe, Midtrans, dan Xendit, supaya:

  • Base URL tetap stabil walau backend dipindah server/port
  • Alamat/port backend asli tidak pernah terekspos ke publik
  • Bisa ganti provider hosting backend kapan saja tanpa merchant perlu update kode integrasi apa pun
⚠️ Base URL WAJIB HTTPS di production — API Key dikirim di header tiap request, kalau lewat HTTP biasa bisa disadap di jaringan publik (WiFi umum, dsb). Netlify otomatis menerbitkan sertifikat SSL gratis untuk custom domain begitu DNS tersambung — kalau domain Anda baru dipasang dan masih menampilkan http://, tunggu beberapa menit sampai SSL aktif sebelum dipakai untuk transaksi sungguhan.

SDK Download

SDK resmi membungkus pemanggilan API + verifikasi signature webhook supaya Anda tidak perlu menulis boilerplate HTTP request sendiri. Isi tiap ZIP: source code, README, contoh integrasi, contoh webhook, contoh callback, contoh error handling, contoh auto order, contoh konfigurasi.

🟢 Node.js SDK

Untuk aplikasi Node.js umum / Express / bot Telegram & Discord.

⬇ Download ZIP
🐘 PHP SDK

Untuk PHP native maupun sebagai basis integrasi Laravel.

⬇ Download ZIP
▲ NestJS SDK Segera

Pakai Node.js SDK di atas untuk sementara — API-nya sama persis.

🔺 Laravel SDK Segera

Pakai PHP SDK di atas untuk sementara, sudah kompatibel Laravel Http:: facade.

🐍 Python SDK Segera

Lihat tab kode Python di tiap endpoint sebagai referensi sementara.

🐹 Go SDK Segera

Lihat tab kode Go di tiap endpoint sebagai referensi sementara.

☕ Java SDK Segera

Lihat tab kode Java di tiap endpoint sebagai referensi sementara.

🦋 Flutter SDK Segera

Lihat tab kode Flutter di tiap endpoint sebagai referensi sementara.

✈️ Telegram Bot SDK Segera

Pakai Node.js SDK + contoh Telegraf di tab "Telegram Bot" tiap endpoint.

🎮 Discord Bot SDK Segera

Pakai Node.js SDK + contoh discord.js di tab "Discord Bot" tiap endpoint.

Kami sengaja jujur soal status: Node.js & PHP sudah SDK sungguhan yang bisa langsung dipakai. SDK bahasa lain masih roadmap — tab kode di tiap endpoint di halaman ini tetap 100% akurat dan bisa langsung dipakai walau belum dibungkus jadi package resmi.

QRIS — Create Payment

Generate QRIS baru untuk satu transaksi. Endpoint ini benar-benar memanggil Pakasir dan membuat baris transaksi baru di database — bukan simulasi.

POST /merchant/payments
FieldTipeWajibKeterangan
amountnumberYaNominal dalam Rupiah, minimum 1.000
referenceIdstringYaID unik dari sistem Anda (order ID), dipakai mencocokkan pembayaran

🧪 API Explorer — Coba Langsung (Request Sungguhan)

Form ini benar-benar memanggil POST /api/v1/merchant/payments pakai API Key Anda sendiri — QRIS yang muncul adalah QRIS ASLI dari Pakasir, bukan contoh/simulasi. Baris transaksi baru akan tercatat di dashboard Anda.

Transaction — Cek Status

Cek status transaksi kapan saja (untuk polling dari sisi Anda, walau kami sarankan pakai Webhook supaya real-time tanpa polling).

GET /merchant/payments/{id}
StatusArti
PENDINGQRIS dibuat, menunggu pembayaran
PAIDPembayaran diterima & dikonfirmasi
EXPIREDMelewati batas waktu, tidak dibayar
FAILEDGagal diproses gateway

Simulasi Pembayaran Sandbox Only

Endpoint ini SENGAJA disediakan Pakasir khusus mode sandbox, supaya Anda bisa test alur webhook tanpa scan QRIS asli. Otomatis ditolak (403) kalau project Anda sudah mode Live — bukan fitur "simulasi" yang menggantikan pembayaran asli.

POST /merchant/payments/{id}/simulate-paid

Withdraw Roadmap

Withdraw lewat Merchant API (tarik dana hasil penjualan langsung dari kode Anda) belum tersedia — kami jujur soal ini daripada mendokumentasikan endpoint yang belum ada.

Saat ini withdraw hanya tersedia untuk pemilik akun wallet pribadi (bukan endpoint merchant), lewat aplikasi web DompetPay langsung atau bot Telegram pribadi Anda (/withdraw <jumlah> <bank> <no_rekening>), dengan approval manual admin demi keamanan. Endpoint Withdraw untuk merchant ada di roadmap kami berikutnya.

Merchant

Endpoint untuk mengelola pengaturan akun merchant Anda — semuanya butuh Bearer Token (login dulu), bukan API Key.

💡 Cara paling gampang: gak perlu manggil API di bawah manual — buka Settings → Integrasi API di akun Anda, tiap API Key ada kolom Webhook URL + tombol Simpan langsung di situ. Endpoint di bawah ini yang dipanggil di baliknya kalau Anda mau integrasi dari sistem sendiri (bukan lewat web kami).

Atur Webhook URL

PATCH /merchant/api-keys/{id}/webhook

Wajib HTTPS. {id} adalah ID API Key (didapat dari response Buat API Key atau Daftar API Key), BUKAN API Key itu sendiri.

User

Ambil data profil akun yang sedang login (Bearer Token) — dipakai kalau Anda membangun dashboard sendiri di atas akun DompetPay pengguna Anda.

GET /users/me

Statistics Roadmap

Endpoint ringkasan statistik transaksi (total omzet, grafik harian, dsb) lewat API belum tersedia. Untuk sekarang, data ini bisa dilihat langsung di Dashboard web. Endpoint GET /merchant/statistics ada di roadmap kami.

Webhook

Webhook adalah notifikasi server-to-server yang kami kirim ke Webhook URL Anda setiap ada perubahan status pembayaran — cara paling reliable untuk tahu transaksi sudah dibayar, tanpa perlu polling.

Cara Kerja

  1. User scan & bayar QRIS
  2. Pakasir mengonfirmasi pembayaran ke server DompetPay
  3. Server DompetPay mengirim POST ke Webhook URL Anda, berisi payload transaksi + header signature
  4. Server Anda WAJIB verifikasi signature sebelum memproses (lihat di bawah)
  5. Server Anda balas HTTP 200 dalam <10 detik — kalau tidak, kami anggap gagal & retry

Contoh Payload

{
  "event": "payment.paid",
  "paymentRequestId": "pay_9f21ac...",
  "referenceId": "ORDER-1234",
  "amount": 50000,
  "status": "PAID",
  "paidAt": "2026-07-19T10:15:00.000Z"
}

Signature Verification

Tiap request webhook membawa header X-DompetPay-Signature — HMAC-SHA256 dari body mentah (raw, sebelum di-parse JSON), pakai Webhook Secret Anda sebagai key. WAJIB diverifikasi supaya tidak ada pihak lain yang bisa memalsukan notifikasi "sudah dibayar".

import crypto from 'crypto';

app.post('/webhook/dompetpay', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-dompetpay-signature'];
  const expected = crypto
    .createHmac('sha256', process.env.DOMPETPAY_WEBHOOK_SECRET)
    .update(req.body) // raw body, BUKAN hasil JSON.parse
    .digest('hex');

  if (signature !== expected) return res.status(401).send('Invalid signature');

  const payload = JSON.parse(req.body);
  if (payload.event === 'payment.paid') {
    // update status order di database Anda pakai payload.referenceId
  }
  res.status(200).send('OK');
});

Retry & Timeout

Timeout tunggu response10 detik
Percobaan ulang3x (1 menit, 5 menit, 15 menit setelah gagal)
Dianggap suksesResponse HTTP 2xx apa pun
Dianggap gagalNon-2xx, timeout, atau koneksi refused

🧪 Webhook Tester

Kirim webhook percobaan SUNGGUHAN (bukan simulasi lokal) ke URL Anda, lengkap signature HMAC asli — supaya Anda bisa test endpoint penerima webhook tanpa perlu bayar QRIS beneran dulu.

Callback

Beda dengan Webhook (server-to-server, diam-diam di belakang layar), Callback URL adalah halaman yang dilihat USER setelah selesai membayar — mirip halaman "Terima kasih" di e-commerce.

  • Menerima callback: user diarahkan browser mereka ke Callback URL Anda dengan query string ?referenceId=ORDER-1234&status=PAID
  • Validasi: JANGAN percaya query string ini untuk update status final (bisa dimanipulasi user) — cukup pakai untuk tampilan "Pembayaran berhasil!", validasi SUNGGUHAN tetap lewat Webhook server-to-server
  • Update status: selalu jadikan Webhook sebagai satu-satunya sumber kebenaran status transaksi, Callback murni untuk UX

Error Code

HTTPKodePesanSolusi
400BAD_REQUESTBody/parameter tidak validCek field wajib & tipe data sesuai tabel di tiap endpoint
401UNAUTHORIZEDAPI Key/token tidak ada atau tidak validCek header X-API-Key/Authorization terkirim benar
403FORBIDDENTidak punya akses ke resource iniPastikan ID milik akun Anda sendiri, atau role cukup (endpoint admin)
404NOT_FOUNDResource tidak ditemukanCek ID benar, transaksi belum expired dari sistem
409CONFLICTData sudah ada/duplikatMis. email/referenceId sudah dipakai sebelumnya
429TOO_MANY_REQUESTSRate limit terlampauiLihat Rate Limit, tunggu sampai window reset
500INTERNAL_ERRORKesalahan tak terduga di serverCoba lagi; kalau berulang, hubungi Support dengan request ID

Rate Limit

Berlaku per API Key / per akun, bukan per IP — jadi aman dipakai di belakang proxy/load balancer manapun.

30
Request / menit (default)
HTTP 429
Response saat limit terlampaui
60 detik
Window reset otomatis

Sisa kuota & waktu reset dikirim di header response tiap request (X-RateLimit-Remaining, X-RateLimit-Reset) — cek header response API Explorer di atas untuk lihat contoh nyatanya.

Changelog

19 Jul 2026

Dokumentasi v2 + perbaikan infrastruktur

Base URL Merchant API resmi jadi /api/v1. Bot login & bot admin pindah ke long polling (tidak butuh HTTPS/domain publik backend lagi). OTP email sekarang benar-benar terkirim lewat SMTP.

Jul 2026

Login Google via JWKS

Verifikasi token Google tidak lagi butuh service account di backend — cukup project ID publik.

Jul 2026

Payment Gateway: Pakasir (QRIS)

QRIS live lewat Pakasir, withdraw manual dengan approval admin via bot Telegram.

FAQ

Supaya base URL tetap stabil selamanya walau backend kami pindah server/port — sama seperti praktik Stripe/Midtrans/Xendit. Anda tidak perlu update kode integrasi kapan pun infrastruktur kami berubah.
Demi keamanan, API Key tidak pernah disimpan dalam bentuk yang bisa ditampilkan ulang. Kalau lupa/hilang, cabut (revoke) key lama dan buat yang baru dari Settings → Integrasi API.
Cek 3 hal: (1) Webhook URL sudah diisi & HTTPS valid di pengaturan merchant, (2) server Anda balas HTTP 2xx dalam 10 detik, (3) coba dulu pakai Webhook Tester di halaman ini untuk isolasi apakah masalah di sisi Anda atau kami.
Tidak disarankan — API Key akan terlihat siapa pun yang buka DevTools browser. Selalu panggil dari server Anda (Node.js/PHP/dst), baru frontend memanggil server Anda sendiri. Lihat contoh tab "Next.js" di endpoint QRIS untuk pola yang aman.

Support