BayarBayar.in

BayarBayar.in Payment API · v2.0

Terima pembayaran QRIS dari aplikasi Anda

Diperbarui 27 Juli 2026 · Base URL: https://bayarbayar.in

Satu panduan lengkap untuk membuat tagihan, mengarahkan pelanggan ke halaman pembayaran, menerima pemberitahuan pembayaran, dan memastikan pesanan aman diproses.

Mulai cepat

BayarBayar.in dipanggil dari backend website atau aplikasi Anda. API key tidak boleh ditempatkan di HTML, JavaScript browser, aplikasi pelanggan, URL pembayaran, atau repository publik.

1Buat transaksiBackend mengirim order dan nominal.
2Buka payment URLPelanggan melihat dan memindai QRIS.
3BayarBayar.in memeriksa mutasiBrowser pelanggan tidak mengakses GoPay.
4Webhook dikirimBackend menerima status bertanda tangan.
5Verifikasi & penuhiPastikan transaksi live benar-benar completed.

Endpoint yang tersedia

Contoh transaksi pertama

Jalankan dari backend atau terminal
curl -X POST 'https://bayarbayar.in/api/transactioncreate/qris' \
  -H 'Content-Type: application/json' \
  -H 'X-API-Key: gpk_test_GANTI_DENGAN_KEY_ANDA' \
  -H 'Idempotency-Key: checkout-INV-001' \
  -d '{
    "project": "toko-satu",
    "order_id": "INV-001",
    "amount": 10000,
    "expiry_minutes": 60
  }'

Jika berhasil, buka nilai payment.payment_url dari response pada browser pelanggan. Jangan membuat sendiri URL pembayaran jika response sudah menyediakannya.

Kapan pesanan boleh diproses? Hanya setelah backend Anda menerima atau membaca status: "completed", memastikan environment: "live", dan mencocokkan project, order ID, serta nominal asli.

A. Persiapan

Daftar atau masuk ke Dashboard BayarBayar.in, lalu buat satu project untuk setiap website atau aplikasi yang akan menerima pembayaran.

A.1. Project

Project memisahkan transaksi, API key, callback URL, webhook secret, rate limit, dan QRIS. Catat dua nilai berikut setelah project dibuat:

  • project slug — identitas project pada setiap request API.
  • API key — credential rahasia yang hanya ditampilkan saat dibuat.
Jangan kirim credential ke browser pelanggan API key dan webhook secret hanya boleh disimpan pada backend merchant atau secret manager.

A.2. QRIS dan akun GoPay Merchant

  1. Buka menu Keamanan dan hubungkan akun GoPay Merchant milik Anda.
  2. Buka menu Project, lalu tambahkan QRIS statis milik merchant yang sama.
  3. Mulai dari mode Sandbox. Ubah ke Live setelah tes integrasi berhasil.

Setiap akun member memakai sesi provider dan QRIS miliknya sendiri. Satu Merchant ID provider tidak dapat dipakai oleh dua akun member.

A.3. Sandbox dan Live

ModeFungsiUang nyata
sandboxMenguji create, payment page, status, dan webhook melalui simulasi dashboard.Tidak
liveMembuat QRIS dinamis dan mencocokkan mutasi akun GoPay Merchant terkait.Ya

B. Halaman pembayaran

Cara yang disarankan adalah membuat transaksi melalui API, lalu mengarahkan pelanggan ke nilai payment.payment_url dari response. URL ini memakai token acak dan tidak mengekspos tuple invoice.

GEThttps://bayarbayar.in/pay/t/{payment_token}

Endpoint kompatibilitas berikut juga tersedia untuk transaksi yang sudah dibuat. Gunakan total_payment, bukan nominal asli.

URL kompatibilitas
https://bayarbayar.in/pay/toko-satu/10123?order_id=INV-001&qris_only=1
ParameterKeterangan
projectSlug project.
amounttotal_payment dari response create.
order_idNomor invoice pada sistem merchant.
redirectURL tujuan setelah lunas. Hostname wajib terdaftar pada redirect allowlist project.
qris_only=1Parameter kompatibilitas. Halaman saat ini memang hanya menampilkan QRIS, sehingga parameter ini tidak mengubah perilaku.
Perlakukan payment URL sebagai data terbatas URL boleh diberikan kepada pelanggan yang akan membayar, tetapi jangan menaruhnya pada halaman publik, log analytics, atau hasil pencarian. API key tidak pernah diperlukan pada halaman pembayaran.

Halaman pembayaran membaca status dari database BayarBayar.in. Setelah pembayaran terverifikasi, QR dan countdown hilang, lalu diganti tanda berhasil. Jika parameter redirect valid, pelanggan dapat kembali ke website merchant.

C. Autentikasi API

Kirim API key melalui header X-API-Key. Header selalu diprioritaskan jika credential lama juga ada di body atau query.

HTTP header
X-API-Key: gpk_live_CONTOH_BUKAN_CREDENTIAL_ASLI
Kompatibilitas lama Parameter api_key pada body atau query masih diterima, tetapi deprecated. Integrasi baru wajib memakai header.

API key memiliki environment dan scope. Key sandbox tidak dapat dipakai setelah project berpindah ke live; simpan key baru yang ditampilkan saat pergantian mode.

C.1. Header yang digunakan

HeaderWajibKeterangan
Content-TypePOSTGunakan application/json.
X-API-KeyYaAPI key project. Jangan kirim ke browser pelanggan.
Idempotency-KeyCreateSangat disarankan agar retry tidak membuat transaksi ganda.
X-Request-IDTidakID penelusuran milik Anda. BayarBayar.in selalu mengembalikannya pada response.

C.2. Scope API key

ScopeDipakai untuk
transactions:writeMembuat dan membatalkan transaksi.
transactions:readMembaca detail transaksi dan metode pembayaran.

Gunakan key dengan scope minimum yang diperlukan. Jika key diduga bocor, buat key baru dari Dashboard dan cabut key lama.

D. API: Transaction Create

Membuat satu transaksi QRIS. Jika kode unik aktif, BayarBayar.in menambah kode tersebut ke nominal asli agar mutasi dapat dicocokkan dengan aman.

POST/api/transactioncreate/qris

D.1. Request

Member dapat menentukan expiry untuk setiap transaksi. Gunakan paling banyak satu field expiry. Rentang yang diterima adalah 5–300 menit (5 menit–5 jam). Jika tidak dikirim, BayarBayar.in menggunakan default 60 menit. Nilai di luar rentang selalu ditolak dengan HTTP 422 dan transaksi tidak dibuat.

FieldTipeKeterangan
project wajibstringSlug project, 3–63 karakter.
order_id wajibstringID invoice unik dalam project, maksimum 128 karakter.
amount wajibintegerNominal transaksi asli dalam rupiah, maksimum Rp100.000.000.
expired_atdate-timeWaktu kedaluwarsa ISO 8601 antara 5 menit dan 5 jam sejak request diproses. Untuk batas tepat 5 menit, gunakan expiry_minutes: 5. Jangan kirim bersama field expiry lain.
expiry_minutesintegerDurasi dalam menit. Minimum 5, maksimum 300, default 60. Nilai desimal atau nilai di luar batas ditolak.
expiredintegerAlias lama untuk durasi menit. Gunakan expiry_minutes pada integrasi baru.
expired_minutesintegerAlias lama untuk durasi menit. Gunakan expiry_minutes pada integrasi baru.
api_key deprecatedstringGunakan header X-API-Key.
cURL
curl -X POST 'https://bayarbayar.in/api/transactioncreate/qris' \
  -H 'Content-Type: application/json' \
  -H 'X-API-Key: gpk_live_CONTOH' \
  -H 'Idempotency-Key: checkout-INV-001' \
  -d '{
    "project": "toko-satu",
    "order_id": "INV-001",
    "amount": 10000,
    "expiry_minutes": 90
  }'
Aturan expiry
  • 5, 60, dan 300 diterima.
  • 4, 301, angka desimal, atau lebih dari satu field expiry ditolak dengan HTTP 422.
  • Gunakan expiry_minutes untuk menghindari selisih jam atau latensi jaringan saat menentukan batas.
  • Expiry tidak dapat diubah setelah QR dibuat. Buat transaksi baru jika membutuhkan waktu berbeda.

E_VALIDATION digunakan untuk bentuk request yang tidak valid, termasuk nilai di bawah batas schema, angka desimal, field tidak dikenal, atau beberapa field expiry sekaligus. E_INVALID_EXPIRY digunakan saat nilai yang formatnya valid tetap berada di luar kebijakan waktu, misalnya expiry_minutes: 301 atau expired_at di luar 5–300 menit.

HTTP 422 · expiry di luar batas
{
  "success": false,
  "message": "Waktu kedaluwarsa harus antara 5 menit dan 300 menit.",
  "code": "E_INVALID_EXPIRY",
  "errors": null,
  "request_id": "UUID"
}

D.2. Response sukses

HTTP 201 · application/json
{
  "success": true,
  "payment": {
    "project": "toko-satu",
    "order_id": "INV-001",
    "amount": 10000,
    "fee": 0,
    "total_payment": 10123,
    "payment_method": "qris",
    "payment_number": "000201010212...",
    "expired_at": "2030-01-01T12:00:00.000Z",
    "environment": "live",
    "sandbox": false,
    "payment_url": "https://bayarbayar.in/pay/t/OPAQUE_TOKEN"
  }
}
  • amount adalah nominal transaksi asli.
  • total_payment adalah nominal tepat yang harus dibayar pelanggan.
  • fee tetap 0; kode unik bukan fee.
  • payment_number berisi payload QRIS dinamis pada mode live.
  • payment_url adalah URL siap pakai yang harus dibuka pelanggan.

Create mengembalikan HTTP 201, termasuk saat request idempotent mengembalikan transaksi yang sudah ada. Simpan order_id dan response ini pada database merchant.

Data yang tidak pernah dikembalikan Response publik tidak berisi QRIS statis, session provider, cookie, OTP, access token, API key, atau webhook secret.

D.3. Response gagal

application/json
{
  "success": false,
  "message": "Request tidak valid.",
  "code": "E_VALIDATION",
  "errors": {
    "formErrors": [],
    "fieldErrors": {
      "expiry_minutes": [
        "Nilai harus berupa bilangan bulat minimal 5."
      ]
    }
  },
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}

Untuk error validasi, errors berisi rincian field. Pada error operasional atau autentikasi, nilainya dapat berupa null.

E. API: Transaction Detail

Gunakan endpoint ini sebagai sumber status transaksi. Untuk keputusan fulfillment, cocokkan selalu project, order_id, amount, environment, dan status.

GET/api/transactiondetail
QueryTipeKeterangan
project wajibstringSlug project pemilik transaksi.
order_id wajibstringID invoice yang dikirim saat create.
amount wajibintegerNominal asli, bukan total_payment.
api_key deprecatedstringGunakan header X-API-Key.
cURL
curl --get 'https://bayarbayar.in/api/transactiondetail' \
  -H 'X-API-Key: gpk_live_CONTOH' \
  --data-urlencode 'project=toko-satu' \
  --data-urlencode 'order_id=INV-001' \
  --data-urlencode 'amount=10000'
HTTP 200 · response pending
{
  "transaction": {
    "project": "toko-satu",
    "order_id": "INV-001",
    "amount": 10000,
    "total_payment": 10123,
    "refund_amount": 0,
    "status": "pending",
    "payment_method": "qris",
    "completed_at": null,
    "environment": "live",
    "sandbox": false
  }
}
HTTP 200 · response completed
{
  "transaction": {
    "project": "toko-satu",
    "order_id": "INV-001",
    "amount": 10000,
    "total_payment": 10123,
    "refund_amount": 0,
    "status": "completed",
    "payment_method": "qris",
    "completed_at": "2030-01-01T11:55:00.000Z",
    "environment": "live",
    "sandbox": false
  }
}

Webhook adalah mekanisme utama untuk perubahan status. Endpoint detail cocok sebagai verifikasi tambahan atau rekonsiliasi—bukan untuk polling sangat cepat. Jika perlu polling, gunakan interval wajar dan exponential backoff.

F. API: Transaction Cancel

Membatalkan transaksi yang masih pending. QR dinonaktifkan secara lokal dan kode unik dilepas sesuai guard period. Transaksi completed tidak dapat dibatalkan.

POST/api/transactioncancel
cURL
curl -X POST 'https://bayarbayar.in/api/transactioncancel' \
  -H 'Content-Type: application/json' \
  -H 'X-API-Key: gpk_live_CONTOH' \
  -d '{
    "project": "toko-satu",
    "order_id": "INV-001",
    "amount": 10000
  }'
HTTP 200 · response
{
  "success": true,
  "status": "cancelled",
  "transaction": {
    "project": "toko-satu",
    "order_id": "INV-001",
    "amount": 10000,
    "total_payment": 10123,
    "refund_amount": 0,
    "status": "cancelled",
    "payment_method": "qris",
    "completed_at": null,
    "environment": "live",
    "sandbox": false
  }
}
Pembayaran terlambat setelah cancel atau expiry Jangan otomatis memenuhi pesanan. Mutasi yang tiba setelah transaksi berakhir dapat dipindahkan ke manual_review agar diperiksa manusia.

G. API: Payment Methods

Membaca metode pembayaran yang aktif untuk project.

GET/api/v1/projects/{project}/payment-methods
cURL
curl 'https://bayarbayar.in/api/v1/projects/toko-satu/payment-methods' \
  -H 'X-API-Key: gpk_live_CONTOH'
Response
{
  "success": true,
  "data": [
    {
      "code": "qris",
      "name": "QRIS",
      "status": "active"
    }
  ]
}

H. Contoh Integrasi

H.1. Node.js

JavaScript · backend
const response = await fetch(
  'https://bayarbayar.in/api/transactioncreate/qris',
  {
    method: 'POST',
    headers: {
      'content-type': 'application/json',
      'x-api-key': process.env.BAYARBAYAR_API_KEY,
      'idempotency-key': `checkout-${order.id}`
    },
    body: JSON.stringify({
      project: 'toko-satu',
      order_id: order.id,
      amount: order.amount,
      expiry_minutes: 60
    })
  }
);

const result = await response.json();
if (!response.ok) throw new Error(result.code);

// Arahkan browser pelanggan ke URL ini.
return result.payment.payment_url;

H.2. PHP

PHP · backend
<?php
$orderId = 'INV-001';
$payload = json_encode([
  'project' => 'toko-satu',
  'order_id' => $orderId,
  'amount' => 10000,
  'expiry_minutes' => 60,
]);

$curl = curl_init('https://bayarbayar.in/api/transactioncreate/qris');
curl_setopt_array($curl, [
  CURLOPT_POST => true,
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    'Content-Type: application/json',
    'X-API-Key: ' . getenv('BAYARBAYAR_API_KEY'),
    'Idempotency-Key: checkout-' . $orderId,
  ],
  CURLOPT_POSTFIELDS => $payload,
]);

$response = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
$result = json_decode($response, true);
curl_close($curl);

if ($status < 200 || $status >= 300) {
  throw new RuntimeException($result['code'] ?? 'E_UNKNOWN');
}

header('Location: ' . $result['payment']['payment_url']);
exit;

I. Webhook Pembayaran

BayarBayar.in mengirim HTTP POST ke callback URL project setiap kali status transaksi berubah. Event disimpan sebelum dikirim dan dicoba ulang dengan exponential backoff sampai menerima HTTP 2xx.

I.1. Header

HeaderIsi
X-Gateway-Event-IDUUID unik untuk deduplikasi event.
X-Gateway-TimestampUNIX timestamp saat request ditandatangani.
X-Gateway-SignatureHMAC SHA-256 dalam format hexadecimal.
Content-Typeapplication/json

I.2. Jenis event

EventKapan dikirimTindakan merchant
transaction.completedPembayaran live terverifikasi.Verifikasi payload, lalu penuhi pesanan satu kali.
transaction.sandbox_completedSimulasi sandbox berhasil.Uji integrasi saja; jangan memenuhi pesanan nyata.
transaction.expiredBatas pembayaran terlewati.Tutup invoice pada sistem merchant.
transaction.cancelledMerchant membatalkan transaksi.Tandai invoice dibatalkan.
transaction.manual_reviewPencocokan tidak aman atau ambigu.Jangan fulfillment otomatis; periksa dashboard.
transaction.partially_refundedPengembalian dana sebagian terdeteksi.Catat nilai refund_amount.
transaction.refundedPengembalian dana penuh terdeteksi.Tandai pembayaran telah dikembalikan.

I.3. Payload

transaction.completed
{
  "schema_version": "1.0",
  "event_id": "550e8400-e29b-41d4-a716-446655440000",
  "event_type": "transaction.completed",
  "event_timestamp": "2030-01-01T11:55:01.000Z",
  "project": "toko-satu",
  "order_id": "INV-001",
  "amount": 10000,
  "total_payment": 10123,
  "status": "completed",
  "payment_method": "qris",
  "completed_at": "2030-01-01T11:55:00.000Z",
  "refund_amount": 0,
  "environment": "live",
  "sandbox": false
}

I.4. Verifikasi signature

Hitung signature dari raw request body persis seperti diterima:

Formula
hex(HMAC_SHA256(timestamp + "." + raw_request_body, webhook_secret))
Node.js · Express
import crypto from 'node:crypto';
import express from 'express';

const app = express();

app.post('/webhook/bayarbayar',
  express.raw({ type: 'application/json' }),
	  (req, res) => {
	    const timestamp = req.get('x-gateway-timestamp') || '';
	    const received = req.get('x-gateway-signature') || '';
	    const timestampSeconds = Number(timestamp);
	    const currentSeconds = Math.floor(Date.now() / 1000);
	    const timestampValid = Number.isSafeInteger(timestampSeconds)
	      && Math.abs(currentSeconds - timestampSeconds) <= 300;

	    if (!timestampValid) return res.sendStatus(401);

	    const expected = crypto
	      .createHmac('sha256', process.env.BAYARBAYAR_WEBHOOK_SECRET)
	      .update(`${timestamp}.${req.body.toString('utf8')}`)
	      .digest();

	    const receivedBuffer = /^[a-f0-9]{64}$/.test(received)
	      ? Buffer.from(received, 'hex')
	      : Buffer.alloc(0);
	    const valid = receivedBuffer.length === expected.length
	      && crypto.timingSafeEqual(receivedBuffer, expected);

    if (!valid) return res.sendStatus(401);

    const event = JSON.parse(req.body.toString('utf8'));
    // Deduplikasi event.event_id sebelum fulfillment.
    res.sendStatus(204);
  }
);
Webhook dapat dikirim berkali-kali Simpan event_id, verifikasi signature, tolak timestamp yang berselisih lebih dari 5 menit, lalu proses event secara idempotent. Hanya kembalikan HTTP 2xx setelah event berhasil disimpan.

I.5. Urutan aman menerima webhook

  1. Baca body sebagai raw bytes sebelum JSON parser mengubah formatnya.
  2. Tolak timestamp yang terlalu lama untuk membatasi replay.
  3. Hitung HMAC menggunakan webhook secret project dan bandingkan secara constant-time.
  4. Simpan X-Gateway-Event-ID pada kolom unik. Event yang sama cukup dibalas HTTP 2xx.
  5. Cocokkan project, order ID, amount, status, dan environment dengan data merchant.
  6. Simpan perubahan secara atomik, baru balas HTTP 2xx.

Callback URL wajib memakai HTTPS dan domain publik. Host lokal atau loopback, jaringan privat/reserved, serta URL yang memuat username atau password akan ditolak. Respons selain HTTP 2xx dianggap gagal dan akan dicoba ulang.

J. Idempotensi, retry, dan rate limit

Kirim header Idempotency-Key saat membuat transaksi. Gunakan nilai unik dan stabil untuk satu usaha pembuatan pembayaran, misalnya checkout-{order_id}.

  • Project, order ID, dan nominal yang sama mengembalikan transaksi yang sudah ada.
  • Order ID sama dengan nominal berbeda menghasilkan HTTP 409.
  • Idempotency key sama untuk payload berbeda menghasilkan HTTP 409.
  • Panjang maksimum idempotency key adalah 128 karakter.

Retry yang aman

  • Jika terjadi timeout jaringan, kirim ulang request create dengan body dan Idempotency-Key yang sama.
  • Jangan mengganti order_id hanya karena response pertama terlambat.
  • Retry otomatis hanya untuk kegagalan sementara seperti timeout, HTTP 429, 502, atau 503.
  • Gunakan exponential backoff dengan jitter dan batasi jumlah percobaan.
  • Jangan retry otomatis untuk 400, 401, 403, 404, 409, atau 422 sebelum penyebab request diperbaiki.

Rate limit

BayarBayar.in menerapkan batas global dan batas per project. Saat HTTP 429 diterima, hentikan request sementara dan ikuti header Retry-After. Header berikut dapat disertakan pada response:

HeaderArti
RateLimitInformasi limit global sesuai standar yang digunakan server.
RateLimit-PolicyKebijakan window dan batas rate limit global.
X-RateLimit-LimitBatas request project per menit.
X-RateLimit-RemainingSisa request pada window project saat ini.
Retry-AfterJumlah detik minimum sebelum mencoba kembali.

K. Status dan Error

pending

Menunggu pembayaran.

completed

Pembayaran berhasil terverifikasi.

expired

Melewati batas waktu pembayaran.

cancelled

Dibatalkan oleh merchant.

failed

Pemrosesan transaksi gagal.

manual_review

Mutasi ambigu atau perlu pemeriksaan manual.

partially_refunded

Dana dikembalikan sebagian.

refunded

Dana dikembalikan seluruhnya.

K.1. HTTP status

HTTPArtiContoh kode
400Format request tidak dapat diproses.E_BAD_REQUEST
401API key salah atau tidak tersedia.E_UNAUTHORIZED
403Project, scope, atau akun provider tidak diizinkan.E_INSUFFICIENT_SCOPE
404Endpoint atau transaksi tidak ditemukan.E_TRANSACTION_NOT_FOUND
409Konflik order, idempotensi, nominal, atau status.E_ORDER_AMOUNT_CONFLICT
413Body request melebihi batas 32 KB.E_BODY_TOO_LARGE
422Validasi request gagal.E_VALIDATION
429Rate limit atau kuota pending tercapai.E_RATE_LIMIT
500Error internal tanpa stack trace.E_INTERNAL
502Provider mengembalikan respons tidak valid.E_PROVIDER_UNAVAILABLE
503Sesi provider atau kode unik belum tersedia.E_PROVIDER_SESSION_NOT_READY

Simpan request_id dari response gagal untuk pencarian audit dan troubleshooting.

K.2. Kode error yang sering ditemui

KodePenyebabYang harus dilakukan
E_UNAUTHORIZEDSlug dan API key tidak cocok, key dicabut, kedaluwarsa, atau berbeda mode.Periksa project dan gunakan key aktif dari environment yang sama.
E_INSUFFICIENT_SCOPEAPI key tidak memiliki scope endpoint.Buat key dengan scope read atau write yang diperlukan.
E_PROJECT_INACTIVEProject dinonaktifkan.Aktifkan project dari Dashboard.
E_PROJECT_PAYMENT_CONFIG_REQUIREDMerchant ID atau QRIS project belum lengkap.Tambahkan QRIS milik akun merchant project.
E_BAD_REQUESTJSON rusak atau request tidak dapat dibaca.Perbaiki sintaks JSON dan header Content-Type.
E_BODY_TOO_LARGEBody request melebihi 32 KB.Kirim hanya field API yang didukung.
E_VALIDATIONTipe, field, atau kombinasi parameter tidak sesuai schema.Periksa rincian pada object errors.
E_INVALID_EXPIRYExpiry yang berformat valid berada di luar 5–300 menit.Kirim satu expiry_minutes berupa integer 5–300.
E_ORDER_AMOUNT_CONFLICTOrder ID sudah ada dengan nominal lain.Gunakan nominal semula atau order ID baru.
E_IDEMPOTENCY_CONFLICTIdempotency key dipakai untuk payload berbeda.Gunakan payload semula atau key baru.
E_COMPLETED_CANNOT_CANCELTransaksi sudah lunas.Jangan cancel; jalankan proses refund terpisah bila tersedia.
E_PROVIDER_SESSION_NOT_READYSesi GoPay live belum dapat diverifikasi.Hubungkan ulang akun provider dari menu Keamanan.
E_RATE_LIMITTerlalu banyak request pada project.Ikuti Retry-After dan perlambat request.

L. Pengujian

  1. Pastikan project berada dalam mode Sandbox.
  2. Buka menu Tes QRIS dan buat transaksi uji.
  3. Gunakan tombol simulasi lunas di dashboard. QR sandbox tidak boleh dibayar dengan aplikasi bank.
  4. Pastikan backend menerima webhook dengan environment: "sandbox" dan event_type: "transaction.sandbox_completed".
  5. Periksa detail transaksi melalui API sebelum menguji mode Live.
Aturan fulfillment Hanya transaksi dengan status: "completed", environment: "live", dan identitas order yang cocok yang boleh memenuhi pesanan nyata.

M. Checklist sebelum menerima uang nyata

Selesaikan seluruh pemeriksaan ini sebelum mengubah project ke mode Live.

Status layanan

GET/healthMenandakan proses aplikasi hidup.
GET/readyHTTP 200 jika database siap; HTTP 503 jika belum siap.

Gunakan endpoint ini untuk load balancer atau monitoring. Jangan menggunakannya sebagai bukti bahwa akun provider suatu project siap menerima pembayaran; pemeriksaan provider tetap dilakukan saat transaksi live dibuat.

N. Pemecahan masalah

QR sandbox tidak dapat dibayar

Ini normal. QR sandbox hanya untuk simulasi melalui menu Tes QRIS. Ubah project ke Live hanya setelah seluruh integrasi selesai diuji.

Pembayaran live sudah dilakukan, tetapi status masih pending

Pastikan pelanggan membayar persis total_payment, Merchant ID sesuai QRIS project, sesi GoPay terhubung, transaksi belum kedaluwarsa, dan worker berjalan. Jangan mengubah status secara manual. Jika pencocokan tidak tunggal atau pembayaran terlambat, transaksi dapat masuk manual_review.

Create mengembalikan 401 setelah mode project diubah

Perubahan Sandbox/Live menghasilkan credential environment yang sesuai. Gunakan API key baru yang ditampilkan setelah perubahan mode.

Webhook terus dicoba ulang

Pastikan callback dapat diakses melalui HTTPS publik, tidak melakukan redirect, selesai sebelum timeout, dan mengembalikan HTTP 2xx. Periksa riwayat webhook pada Dashboard.

Payment URL menampilkan 404

Gunakan payment_url persis dari response create. Token yang salah, project nonaktif, atau URL yang dipotong akan ditolak.

Bagaimana meminta bantuan?

Catat waktu kejadian, project slug, order ID, HTTP status, error code, dan request_id. Jangan pernah mengirim API key, webhook secret, OTP, cookie, atau session provider.