Dokumentasi API
REST API untuk membuat QRIS dinamis dari akun GoPay Merchant kamu dan mengecek pembayaran masuk, dari website atau aplikasi mana pun. Semua respons berformat JSON.
Hubungkan akun GoPay kamu lewat dashboard (login OTP, sekali saja), lalu panggil endpoint di bawah dengan API key kamu.
Base URL dan autentikasi
Setiap akun punya base URL dan API key sendiri. Ambil keduanya di halaman Pengaturan. {ID_AKUN} adalah ID unik akunmu — URL lengkapnya muncul otomatis saat kamu login.
https://gw.gopaygateway.shop/t/{ID_AKUN}
Kirim API key di header X-Api-Key pada setiap request (atau lewat query ?api_key=). Panggil API dari server, bukan dari browser pembeli, supaya API key tidak terlihat.
X-Api-Key: API_KEY_KAMU
Alur integrasi
- Saat pembeli checkout, backend kamu memanggil
POST /create-qrisdengan nominal pesanan. Simpantrx_id(danqris_id) di data pesanan. - Tampilkan QR ke pembeli: arahkan ke
qris_url, atau render sendiri dariqris_code. - Tahu pembayaran masuk dengan salah satu cara:
- Callback (disarankan): set URL callback sekali di Pengaturan. Gateway otomatis POST ke URL itu begitu QRIS dibayar — tanpa polling.
- Polling: panggil
GET /check-paymentatauGET /transaction/{qris_id}secara berkala.
QRIS berlaku 5 menit. Kalau memakai polling, beri jeda minimal 8 detik antar pengecekan; pengecekan yang terlalu sering bisa memicu pembatasan akun GoPay. Callback tidak kena batasan itu karena gateway yang memeriksa.
/create-qrisMembuat QRIS dinamis dari QRIS statis toko. Menerima body JSON (POST) atau query string (GET). QRIS statis harus sudah diatur di halaman GoPay.
Parameter
| Nama | Tipe | Keterangan |
|---|---|---|
amount | number | Wajib. Nominal dalam Rupiah, lebih dari 0. |
merchant_ref | string | Opsional. ID pesanan dari sistem kamu (maks 64 karakter). Dikembalikan apa adanya di respons dan di callback, untuk mencocokkan pembayaran dengan pesanan. |
Contoh request
curl -X POST https://gw.gopaygateway.shop/t/{ID_AKUN}/create-qris \
-H "X-Api-Key: API_KEY_KAMU" \
-H "Content-Type: application/json" \
-d '{"amount": 25000}'
use Illuminate\Support\Facades\Http;
$res = Http::withHeaders(['X-Api-Key' => $apiKey])
->post('https://gw.gopaygateway.shop/t/{ID_AKUN}/create-qris', ['amount' => 25000]);
$qris = $res->json('data');
// Simpan $qris['trx_id'] di pesanan, arahkan pembeli ke $qris['qris_url']
const res = await fetch('https://gw.gopaygateway.shop/t/{ID_AKUN}/create-qris', {
method: 'POST',
headers: { 'X-Api-Key': process.env.GATEWAY_API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ amount: 25000 })
});
const { data } = await res.json();
Contoh respons
{
"success": true,
"data": {
"qris_id": "abc123xy",
"trx_id": "TRX-A3F8K2M9",
"merchant_ref": "INV-00123",
"qris_url": "https://gw.gopaygateway.shop/t/{ID_AKUN}/qr/abc123xy",
"qris_code": "00020101021226...",
"amount": 25000,
"expires_in": "5 menit"
}
}
/check-paymentMencari transaksi masuk yang nominalnya cocok. Satu transaksi hanya bisa diklaim oleh satu trx_id, jadi dua pesanan dengan nominal sama tidak saling mengklaim. Menerima query string (GET) atau body JSON (POST).
Parameter
| Nama | Tipe | Keterangan |
|---|---|---|
amount | number | Wajib. Nominal yang dicari. |
trx_id | string | Sangat disarankan. Nilai trx_id dari /create-qris. |
Contoh request
curl "https://gw.gopaygateway.shop/t/{ID_AKUN}/check-payment?amount=25000&trx_id=TRX-A3F8K2M9" \
-H "X-Api-Key: API_KEY_KAMU"
Respons: sudah dibayar
{
"success": true,
"paid": true,
"transaction": {
"transaction_id": "gopay-internal-tx-id",
"order_id": "GP-1234567890",
"amount": 25000,
"payer_issuer": "GoPay / Bank",
"payment_type": "QRIS",
"transaction_time": "2026-10-12T00:15:12.000Z"
}
}
Respons: belum dibayar
{
"success": true,
"paid": false,
"message": "Pembayaran belum ditemukan atau sudah pernah diklaim"
}
/transaction/{qris_id}Mengecek status satu transaksi berdasarkan qris_id dari /create-qris. Berguna sebagai cadangan bila callback belum sampai. Butuh API key.
Contoh request
curl https://gw.gopaygateway.shop/t/{ID_AKUN}/transaction/abc123xy \
-H "X-Api-Key: API_KEY_KAMU"
Contoh respons
{
"success": true,
"status": "PAID",
"paid": true,
"data": {
"qris_id": "abc123xy",
"trx_id": "TRX-A3F8K2M9",
"merchant_ref": "INV-00123",
"amount": 25000,
"status": "PAID",
"transaction": {
"transaction_id": "gopay-internal-tx-id",
"order_id": "GP-1234567890",
"amount": 25000,
"payer_issuer": "GoPay / Bank",
"payment_type": "QRIS",
"transaction_time": "2026-10-12T00:15:12.000Z"
}
}
}
Nilai status: PENDING, PAID, EXPIRED, atau NOT_FOUND (HTTP 404). Objek transaction hanya terisi saat PAID.
/transactionsMengambil daftar transaksi masuk (3 hari terakhir).
Parameter
| Nama | Tipe | Keterangan |
|---|---|---|
pageSize | number | Opsional. Jumlah transaksi (maks 100). Default: 20. |
Contoh request
curl "https://gw.gopaygateway.shop/t/{ID_AKUN}/transactions?pageSize=10" \
-H "X-Api-Key: API_KEY_KAMU"
Contoh respons
{
"success": true,
"total_amount": "25000",
"data": {
"transactions": [
{
"amount": 25000,
"status": "settlement",
"time": "2026-10-12T00:15:12.000Z",
"issuer": "GoPay / Bank",
"order_id": "GP-1234567890",
"transaction_id": "gopay-internal-tx-id"
}
]
}
}
/token-statusMemeriksa apakah sesi GoPay Merchant masih aktif. Berguna untuk pemantauan.
curl https://gw.gopaygateway.shop/t/{ID_AKUN}/token-status \
-H "X-Api-Key: API_KEY_KAMU"
{
"success": true,
"data": { "token_status": "valid", "message": "Token dan Sesi GoPay Merchant Aktif" }
}
/qr/{qris_id}Halaman pembayaran siap pakai untuk pembeli: gambar QR, hitung mundur 5 menit, dan tombol cek status. Tidak butuh API key, jadi aman dibuka di browser pembeli. Tambahkan ?format=raw untuk dialihkan langsung ke gambar QR.
https://gw.gopaygateway.shop/t/{ID_AKUN}/qr/abc123xy
/api/qr-status/{qris_id}Status pembayaran untuk satu QRIS. Tidak butuh API key, jadi boleh dipanggil dari frontend kamu sendiri.
{
"success": true,
"paid": false,
"status": "PENDING",
"message": "Belum ada pembayaran masuk"
}
Nilai status: PENDING, PAID, EXPIRED, atau NOT_FOUND. Saat PAID, respons menyertakan objek transaction.
Callback (Webhook)
Daripada polling, gateway bisa memberitahu website kamu otomatis. Set URL Callback sekali di halaman Pengaturan. Setelah itu, setiap QRIS yang dibayar (atau kedaluwarsa) memicu request POST berisi JSON ke URL tersebut.
- Gateway mendeteksi pembayaran (dari buka halaman QR pembeli maupun dari pengecekan latar belakang tiap ~10 detik).
- Gateway mengirim
POSTJSON ke URL callback kamu dengan header tanda tangan. - Endpoint kamu memverifikasi tanda tangan, menandai pesanan lunas, lalu membalas
HTTP 200secepatnya.
Bila endpoint tidak membalas 2xx, gateway mengulang pengiriman sampai 4 kali dengan jeda menaik (1s, 2s, 4s). Riwayat pengiriman terakhir tampil di halaman Pengaturan. Callback dikirim satu kali per transaksi saat berhasil (2xx).
Header request
| Header | Keterangan |
|---|---|
X-Callback-Event | payment.success atau payment.expired. |
X-Callback-Signature | HMAC‑SHA256 (hex) dari raw body, memakai signature secret kamu. |
Content-Type | application/json |
(URL callback kamu)Isi body (JSON) yang dikirim gateway ke URL callback kamu:
| Field | Tipe | Keterangan |
|---|---|---|
event | string | payment.success atau payment.expired. |
status | string | PAID atau EXPIRED. |
provider | string | Sumber pembayaran, mis. gopay. |
trx_id | string | ID transaksi dari /create-qris. |
qris_id | string | ID QRIS dari /create-qris. |
merchant_ref | string | ID pesanan milikmu, bila tadi dikirim. Bisa null. |
amount | number | Nominal dalam Rupiah. |
reference | string | ID transaksi internal GoPay (saat PAID). |
payer_issuer | string | Penerbit pembayar, mis. GoPay / Bank. |
paid_at | string | Waktu transaksi (ISO 8601), saat PAID. |
Contoh body
{
"event": "payment.success",
"status": "PAID",
"provider": "gopay",
"trx_id": "TRX-A3F8K2M9",
"qris_id": "abc123xy",
"merchant_ref": "INV-00123",
"amount": 25000,
"reference": "gopay-internal-tx-id",
"order_id": "GP-1234567890",
"payer_issuer": "GoPay / Bank",
"payment_type": "QRIS",
"paid_at": "2026-10-12T00:15:12.000Z"
}
Verifikasi signature
Selalu verifikasi sebelum memproses: hitung HMAC‑SHA256 dari raw body (byte mentah, sebelum di-parse) memakai signature secret dari halaman Pengaturan, lalu bandingkan dengan header X-Callback-Signature. Tolak bila tidak cocok.
Route::post('/gateway/callback', function (Request $request) {
$secret = config('services.gateway.callback_secret');
$expected = hash_hmac('sha256', $request->getContent(), $secret);
if (! hash_equals($expected, $request->header('X-Callback-Signature', ''))) {
abort(401, 'Invalid signature');
}
$p = $request->json();
if ($p->get('status') === 'PAID') {
// tandai pesanan $p->get('merchant_ref') lunas (idempoten)
}
return response()->json(['ok' => true]); // balas 200 cepat
});
const crypto = require('crypto');
// penting: baca RAW body, bukan hasil parse
app.post('/gateway/callback', express.raw({ type: 'application/json' }), (req, res) => {
const expected = crypto.createHmac('sha256', process.env.GATEWAY_CALLBACK_SECRET)
.update(req.body).digest('hex');
const got = req.get('X-Callback-Signature') || '';
if (expected.length !== got.length ||
!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(got))) {
return res.status(401).send('Invalid signature');
}
const p = JSON.parse(req.body.toString());
if (p.status === 'PAID') {
// tandai pesanan p.merchant_ref lunas (idempoten)
}
res.json({ ok: true });
});
import hmac, hashlib
from flask import request, abort
@app.post("/gateway/callback")
def gateway_callback():
raw = request.get_data() # raw body, sebelum parse
expected = hmac.new(SECRET.encode(), raw, hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, request.headers.get("X-Callback-Signature", "")):
abort(401)
p = request.get_json()
if p["status"] == "PAID":
pass # tandai pesanan p["merchant_ref"] lunas (idempoten)
return {"ok": True}
Proses callback secara idempoten: callback yang sama bisa terkirim lebih dari sekali bila endpoint kamu sempat lambat/gagal. Pakai trx_id atau merchant_ref sebagai kunci agar pesanan tidak diproses dua kali.
Kode error
| HTTP | Arti | Yang perlu dilakukan |
|---|---|---|
| 401 | API key salah atau tidak dikirim | Periksa header X-Api-Key. |
| 400 | Parameter tidak valid, atau GoPay belum terhubung | Periksa amount, lalu cek halaman GoPay di dashboard. |
| 500 | QRIS statis belum diatur, atau GoPay menolak permintaan | Baca message atau error pada respons. |
{
"success": false,
"message": "Autentikasi Gagal: API Key tidak valid"
}