Panduan Memulai
Ikuti 6 langkah berikut untuk menerima pembayaran QRIS pertama Anda.
- 1
Daftar akun
Buka /register (email atau Google). Paket trial gratis otomatis aktif bila disediakan admin. Jika tidak, pilih paket di menu Langganan.
- 2
Siapkan QRIS statis
Buka aplikasi GoBiz (atau stiker QRIS Gojek), scan kode QR dengan aplikasi pemindai QR biasa, lalu salin teks hasilnya. Teks diawali
000201dan berakhir dengan 4 karakter CRC. - 3
Hubungkan GoPay
Menu Hubungkan GoPay → masukkan nomor HP merchant → masukkan kode OTP yang dikirim lewat SMS/WhatsApp → pilih merchant dan tempel string QRIS statis. OTP tidak disimpan; token disimpan terenkripsi dan bisa dihapus lewat tombol Putuskan.
- 4
Uji lewat dashboard
Menu Pembayaran → Buat tagihan uji dengan nominal kecil (mis. Rp1.000). Bayar QR yang muncul memakai e-wallet apa pun. Status akan berubah menjadi Lunas otomatis dan notifikasi muncul realtime.
- 5
Buat API key
Menu API & Webhook → Buat key. Salin key (diawali
iak_) dan simpan sebagai environment variable di server Anda. Key tidak akan ditampilkan lagi. - 6
Pasang webhook (disarankan)
Isi URL webhook default di menu yang sama, tekan Kirim webhook tes, lalu verifikasi signature seperti contoh pada bagian Verifikasi Signature.
Autentikasi
Sertakan API key pada setiap request lewat header X-API-Key (atau Authorization: Bearer <key>). Semua request dan respons berformat JSON. Gunakan HTTPS dan jangan pernah menaruh API key di kode front-end.
X-API-Key: iak_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Content-Type: application/json
Format respons:
// sukses
{ "success": true, "data": { ... } }
// gagal
{ "success": false, "error": { "code": "invalid_amount", "message": "..." } }Rate limit: 120 request/menit per API key. Berlebih → HTTP 429 rate_limited.
GET /api/v1/account mengembalikan status langganan dan koneksi GoPay — cocok untuk tes API key.
Buat Pembayaran
POST https://pga-pay.vip/api/v1/payment/create
| Parameter | Tipe | Wajib | Keterangan |
|---|---|---|---|
| amount | integer | Ya | Nominal rupiah (1 – 10.000.000), tanpa desimal. |
| reference | string | Tidak | ID order di sistem Anda (maks 100). Idempotent: memanggil ulang dengan reference & amount sama selagi pending mengembalikan tagihan yang sama. |
| description | string | Tidak | Catatan internal (maks 190). |
| expire_minutes | integer | Tidak | Masa berlaku 5 – 1440 menit. Default 30. |
| callback_url | string | Tidak | URL webhook khusus tagihan ini (menimpa webhook default). Harus URL http(s) publik. |
| use_unique_code | boolean | Tidak | Default true. Jika false, tidak ada kode unik; hanya satu tagihan pending per nominal yang sama. |
Contoh request:
curl -X POST https://pga-pay.vip/api/v1/payment/create \
-H "X-API-Key: $AUTOGOPAY_KEY" \
-H "Content-Type: application/json" \
-d '{"amount": 50000, "reference": "INV-90281", "expire_minutes": 30}'<?php
$ch = curl_init('https://pga-pay.vip/api/v1/payment/create');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['X-API-Key: ' . getenv('AUTOGOPAY_KEY'), 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode(['amount' => 50000, 'reference' => 'INV-90281']),
]);
$res = json_decode(curl_exec($ch), true);
if ($res['success']) {
header('Location: ' . $res['data']['payment_url']); // halaman bayar siap pakai
}const res = await fetch('https://pga-pay.vip/api/v1/payment/create', {
method: 'POST',
headers: { 'X-API-Key': process.env.AUTOGOPAY_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify({ amount: 50000, reference: 'INV-90281' }),
});
const { success, data, error } = await res.json();
if (success) console.log(data.payment_url, data.total_amount);import os, requests
r = requests.post('https://pga-pay.vip/api/v1/payment/create',
headers={'X-API-Key': os.environ['AUTOGOPAY_KEY']},
json={'amount': 50000, 'reference': 'INV-90281'}, timeout=15)
body = r.json()
if body['success']:
print(body['data']['payment_url'], body['data']['total_amount'])Respons 201 Created:
{
"success": true,
"data": {
"payment_id": "pay_3f9a1c0b7d2e4a5f6b81",
"reference": "INV-90281",
"description": null,
"status": "pending",
"amount": 50000,
"unique_code": 37,
"total_amount": 50037,
"qris_string": "00020101021226...6304ABCD",
"payment_url": "https://pga-pay.vip/pay/pay_3f9a1c0b7d2e4a5f6b81",
"expires_at": "2026-10-10T15:30:00+07:00",
"paid_at": null,
"created_at": "2026-10-10T15:00:00+07:00",
"idempotent": false
}
}Dua cara menampilkan pembayaran ke pelanggan: (1) arahkan ke payment_url — halaman checkout dengan QR, hitung mundur, dan status live; atau (2) render sendiri qris_string menjadi QR code di aplikasi Anda dan tampilkan total_amount.
Cek Status
GET https://pga-pay.vip/api/v1/payment/status/{payment_id}
{payment_id} boleh berupa payment_id maupun reference milik Anda. Memanggil endpoint ini juga memicu pengecekan mutasi (maks sekali per ±5 detik per akun).
curl https://pga-pay.vip/api/v1/payment/status/INV-90281 -H "X-API-Key: $AUTOGOPAY_KEY"
Status: pending → paid | expired | cancelled. Sebaiknya jadikan webhook sebagai sumber utama dan status polling sebagai cadangan (interval ≥ 5 detik).
Daftar & Batalkan
GET https://pga-pay.vip/api/v1/payment/list?status=paid&limit=20&page=1
Parameter opsional: status (pending|paid|expired|cancelled), limit (1–100), page. Respons berisi payments[] dan pagination.
POST https://pga-pay.vip/api/v1/payment/cancel
curl -X POST https://pga-pay.vip/api/v1/payment/cancel \
-H "X-API-Key: $AUTOGOPAY_KEY" -H "Content-Type: application/json" \
-d '{"payment_id": "pay_3f9a1c0b7d2e4a5f6b81"}'Hanya tagihan pending yang bisa dibatalkan; selain itu → 409 not_cancellable.
Objek Payment
| payment_id | ID unik tagihan (pay_ + 20 hex). |
| reference | ID order dari sistem Anda. |
| status | pending | paid | expired | cancelled. |
| amount | Nominal asal (integer rupiah). |
| unique_code | Kode unik 0–99 yang ditambahkan. |
| total_amount | amount + unique_code — nominal yang harus dibayar pelanggan. |
| qris_string | Payload QRIS dinamis (EMV), render sebagai QR. |
| payment_url | Halaman checkout publik. |
| expires_at / paid_at / created_at | Waktu format ISO 8601 (zona Asia/Jakarta). |
Webhook
Saat status tagihan berubah, kami mengirim POST JSON ke callback_url tagihan atau URL webhook default Anda. Balas dengan HTTP 2xx secepatnya (timeout 8 detik).
Event: payment.paid, payment.expired, payment.cancelled, payment.test (tombol uji).
Header:
Content-Type: application/json User-Agent: AutoGopay-Webhook/1.0 X-AutoGopay-Event: payment.paid X-AutoGopay-Delivery: 1042 X-AutoGopay-Timestamp: 1791626400 X-AutoGopay-Signature: sha256=9b74c9897bac770ffc029102a200c5de...
Body:
{
"event": "payment.paid",
"created_at": "2026-10-10T15:01:12+07:00",
"data": { "payment_id": "pay_3f9a...", "reference": "INV-90281", "status": "paid", "amount": 50000, "total_amount": 50037, "paid_at": "2026-10-10T15:01:12+07:00", ... }
}Retry: bila gagal (non-2xx / timeout), pengiriman diulang dengan jeda 1 mnt, 5 mnt, 15 mnt, 1 jam, 6 jam (maks 6 percobaan). Webhook bisa terkirim lebih dari sekali — buat handler Anda idempoten (cek payment_id sudah diproses atau belum).
Verifikasi Signature
Signature = HMAC-SHA256(secret, timestamp + "." + raw_body) dalam hex. secret ada di menu API & Webhook (diawali whsec_). Selalu hitung dari raw body (bukan hasil re-encode JSON) dan tolak bila timestamp lebih dari 5 menit.
<?php
$secret = getenv('AUTOGOPAY_WEBHOOK_SECRET');
$raw = file_get_contents('php://input');
$ts = $_SERVER['HTTP_X_AUTOGOPAY_TIMESTAMP'] ?? '';
$sig = $_SERVER['HTTP_X_AUTOGOPAY_SIGNATURE'] ?? '';
$expected = 'sha256=' . hash_hmac('sha256', $ts . '.' . $raw, $secret);
if (!hash_equals($expected, $sig) || abs(time() - (int)$ts) > 300) {
http_response_code(401); exit('invalid signature');
}
$evt = json_decode($raw, true);
if ($evt['event'] === 'payment.paid') {
// tandai order $evt['data']['reference'] sebagai LUNAS (idempoten)
}
http_response_code(200); echo 'ok';const crypto = require('crypto');
app.post('/callback', express.raw({ type: 'application/json' }), (req, res) => {
const ts = req.header('X-AutoGopay-Timestamp');
const sig = req.header('X-AutoGopay-Signature') || '';
const expected = 'sha256=' + crypto.createHmac('sha256', process.env.WEBHOOK_SECRET)
.update(ts + '.' + req.body.toString('utf8')).digest('hex');
const ok = sig.length === expected.length && crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
if (!ok || Math.abs(Date.now() / 1000 - Number(ts)) > 300) return res.sendStatus(401);
const evt = JSON.parse(req.body);
if (evt.event === 'payment.paid') { /* tandai lunas (idempoten) */ }
res.sendStatus(200);
});import hmac, hashlib, time, os
from flask import Flask, request, abort
app = Flask(__name__)
@app.post('/callback')
def callback():
raw = request.get_data()
ts = request.headers.get('X-AutoGopay-Timestamp', '')
sig = request.headers.get('X-AutoGopay-Signature', '')
expected = 'sha256=' + hmac.new(os.environ['WEBHOOK_SECRET'].encode(),
ts.encode() + b'.' + raw, hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, sig) or abs(time.time() - int(ts)) > 300:
abort(401)
evt = request.get_json()
if evt['event'] == 'payment.paid':
pass # tandai lunas (idempoten)
return 'ok'Kode Error
| HTTP | code | Arti |
|---|---|---|
| 400 | invalid_json | Body bukan JSON valid. |
| 401 | missing_api_key / invalid_api_key | Header kosong atau key salah/dicabut. |
| 402 | subscription_inactive | Langganan belum aktif / habis. |
| 403 | account_suspended | Akun ditangguhkan admin. |
| 403 | email_unverified | Email akun belum diverifikasi (bila admin mewajibkannya). |
| 404 | not_found | Pembayaran / endpoint tidak ditemukan. |
| 409 | gopay_not_connected | GoPay belum terhubung atau sesi berakhir. |
| 409 | duplicate_reference / reference_in_use | reference sudah lunas / punya tagihan pending berbeda. |
| 409 | too_many_pending / not_cancellable | Slot nominal habis / status tidak bisa dibatalkan. |
| 413 | payload_too_large | Body > 64 KB. |
| 422 | invalid_amount / invalid_expire / invalid_callback_url / invalid_reference | Validasi parameter gagal. |
| 429 | rate_limited | Melebihi 120 request/menit. |
| 500 | server_error | Kesalahan server. |
Praktik Terbaik
- Selalu gunakan
referenceunik per order agar pembuatan tagihan aman diulang (idempotent). - Tampilkan total_amount (bukan amount) dan peringatkan pelanggan untuk membayar persis nominal tersebut.
- Anggap webhook sebagai sumber kebenaran utama; polling status hanya cadangan dan jangan lebih sering dari 5 detik.
- Verifikasi signature + timestamp, dan buat handler idempoten.
- Simpan API key & webhook secret di environment variable; cabut dan buat ulang bila bocor.
- Untuk transaksi bernilai besar, cocokkan juga di aplikasi GoBiz Anda sebelum mengirim barang.
Troubleshooting
Layanan ini memakai antarmuka tidak resmi GoBiz; lihat Syarat & Ketentuan terkait risiko akun.