VitzXPay adalah payment gateway berbasis QRIS yang memungkinkan kamu menerima pembayaran dari semua e-wallet dan mobile banking di Indonesia.
Ikuti 4 langkah berikut untuk mulai menerima pembayaran di website kamu.
/merchant_api/create.php beserta API Key di header.Semua request ke API harus menyertakan API Key proyekmu di header HTTP.
X-Api-Key: vitzpay_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
VitzXPay menyediakan dua endpoint utama — membuat transaksi dan mengecek statusnya.
Buat transaksi QRIS baru dan dapatkan QR code dinamis siap tampil ke pembeli.
| Header | Value | Keterangan |
|---|---|---|
Content-Type |
application/json |
Wajib disertakan |
X-Api-Key |
vitzpay_xxx… |
API Key proyekmu |
| Field | Tipe | Wajib | Keterangan |
|---|---|---|---|
amount |
integer | Wajib | Nominal dalam Rupiah, minimum Rp 100 |
note |
string | Opsional | Catatan transaksi, misal nomor order |
{
"amount": 50000,
"note": "Order #1023"
}
{
"success": true,
"trx_id": "TRX172093412345",
"amount": 50000,
"note": "Order #1023",
"qr_url": "https://api.qrserver.com/v1/create-qr-code/?data=...",
"qris_data": "00020101021226...",
"expired_at": "2026-01-01T12:15:00",
"check_url": "https://yourdomain.com/merchant_api/status.php?trx=TRX..."
}
Cek status pembayaran berdasarkan trx_id yang didapat saat membuat transaksi.
| Parameter | Tipe | Keterangan |
|---|---|---|
trx |
string | TRX ID yang diterima saat create transaksi |
{
"success": true,
"trx_id": "TRX172093412345",
"amount": 50000,
"status": "paid",
"note": "Order #1023",
"paid_at": "2026-01-01 12:08:45",
"expired_at": "2026-01-01 12:15:00"
}
Setiap transaksi memiliki salah satu dari tiga status berikut.
Atur Webhook URL di dashboard proyekmu. VitzXPay akan otomatis mengirim POST ke URL itu setiap kali pembayaran berhasil — tanpa perlu polling.
{
"event": "payment.success",
"trx_id": "TRX172093412345",
"amount": 50000,
"note": "Order #1023",
"paid_at": "2026-01-01 12:08:45"
}
Semua error dikembalikan dalam format JSON dengan success: false dan pesan error.
| HTTP Code | Pesan | Penyebab |
|---|---|---|
| 401 | Invalid API Key |
API Key salah atau tidak ada di header |
| 400 | amount required |
Field amount tidak dikirim |
| 400 | amount minimum Rp 100 |
Nominal di bawah minimum |
| 404 | Transaction not found |
TRX ID tidak ditemukan |
| 500 | Internal Server Error |
Error di sisi server VitzXPay |
{
"success": false,
"message": "Invalid API Key"
}
Contoh lengkap dari membuat transaksi, menampilkan QR, hingga menangani webhook di server.
// ─── 1. Buat Transaksi ──────────────────────────────── $ch = curl_init('https://yourdomain.com/merchant_api/create.php'); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', 'X-Api-Key: vitzpay_xxxxxxxxxxxx' ], CURLOPT_POSTFIELDS => json_encode([ 'amount' => 50000, 'note' => 'Order #' . $order_id ]) ]); $result = json_decode(curl_exec($ch), true); curl_close($ch); // ─── 2. Simpan TRX ID ke database ──────────────────── $trx_id = $result['trx_id']; $qr_url = $result['qr_url']; // ─── 3. Tampilkan QR ke customer ───────────────────── echo '<img src="' . $qr_url . '" alt="QR QRIS" width="250">'; // ─── 4. Terima Webhook (webhook_handler.php) ────────── $payload = json_decode(file_get_contents('php://input'), true); if ($payload['event'] === 'payment.success') { $trx_id = $payload['trx_id']; $amount = $payload['amount']; // UPDATE orders SET status='paid' WHERE trx_id='$trx_id' http_response_code(200); echo 'OK'; }
Alternatif webhook — polling status dari frontend untuk update UI secara realtime tanpa reload.
async function pollPaymentStatus(trxId) {
const url = `/merchant_api/status.php?trx=${trxId}`;
const interval = setInterval(async () => {
try {
const res = await fetch(url);
const data = await res.json();
if (data.status === 'paid') {
clearInterval(interval);
showSuccessUI(data);
notifyServer(data.trx_id);
} else if (data.status === 'expired') {
clearInterval(interval);
showExpiredUI();
}
} catch (err) {
console.error('Polling error:', err);
}
}, 3000); // cek tiap 3 detik
// Batas aman: stop setelah 20 menit
setTimeout(() => clearInterval(interval), 20 * 60 * 1000);
}
pollPaymentStatus('TRX172093412345');