Dokumentasi Vintech Payment
Terima pembayaran untuk bisnis apa pun dalam 3 langkah: buat order → arahkan pelanggan ke payment_url → terima webhook saat lunas.
1. Autentikasi
Setiap bisnis punya Secret Key (vp_sk_…) di panel admin → Bisnis & API. Kirim di header, hanya dari server Anda — jangan pernah di JavaScript browser.
Authorization: Bearer vp_sk_xxxxxxxxxxxxxxxxxxxxxxxx Content-Type: application/json
2. Buat order
POST https://payments.vintech.cloud/api/v1/orders/
curl -X POST https://payments.vintech.cloud/api/v1/orders/ \
-H "Authorization: Bearer vp_sk_xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"external_ref": "ORDER-1042",
"amount": 150000,
"description": "Cetak spanduk 3x1m",
"customer": { "name": "Budi", "email": "budi@email.com", "phone": "0812xxxx" },
"return_url": "https://tokoanda.com/terima-kasih",
"expires_in_minutes": 1440,
"metadata": { "cabang": "Bandung" }
}'
| Field | Wajib | Keterangan |
|---|---|---|
| amount | Ya | Total dalam Rupiah (bilangan bulat, 1.000 – 100.000.000) |
| description | Ya | Judul tagihan yang dilihat pelanggan |
| external_ref | Disarankan | Nomor order di sistem Anda. Mengirim ulang ref yang sama mengembalikan order yang sama (idempotent) |
| customer | Tidak | name, email, phone |
| items | Tidak | Array {name, price, quantity}. Totalnya harus sama dengan amount |
| return_url | Tidak | Pelanggan diarahkan ke sini setelah bayar (default: pengaturan bisnis) |
| expires_in_minutes | Tidak | 5 – 10080 (default 1440 = 24 jam) |
| metadata | Tidak | Objek bebas, dikembalikan apa adanya di webhook |
Respons 201:
{
"id": "PAY-A1B2C3D4E5",
"status": "pending",
"amount": 150000,
"payment_url": "https://payments.vintech.cloud/pay/PAY-A1B2C3D4E5/",
"expires_at": "2026-10-19T10:00:00+07:00",
"external_ref": "ORDER-1042", ...
}
Arahkan pelanggan ke payment_url — selesai. Halaman bayar, QRIS/VA/E-Wallet, dan verifikasi ditangani Vintech Payment.
3. Webhook payment.paid
Saat lunas, kami mengirim POST ke Webhook URL bisnis Anda (diatur di panel admin). Balas dengan HTTP 2xx. Jika gagal, kami mengulang otomatis (1m, 5m, 30m, 2j, 12j).
POST https://tokoanda.com/webhook/vintech
X-VintechPay-Event: payment.paid
X-VintechPay-Signature: t=1760000000,v1=9f2c...e1
{
"event": "payment.paid",
"id": "PAY-A1B2C3D4E5",
"external_ref": "ORDER-1042",
"status": "paid",
"amount": 150000,
"currency": "IDR",
"paid_at": "2026-10-18T10:15:00+07:00",
"customer": { "name": "Budi", "email": "...", "phone": "..." },
"payment": { "type": "bank_transfer", "channel": "bca" },
"metadata": { "cabang": "Bandung" }
}
Verifikasi tanda tangan (wajib): HMAC-SHA256(secret_key, "<t>.<body mentah>") harus sama dengan v1. Tolak jika selisih t > 5 menit.
# Python import hmac, hashlib, time def valid(secret, header, raw_body): parts = dict(p.split("=", 1) for p in header.split(",")) expected = hmac.new(secret.encode(), f"{parts['t']}.{raw_body}".encode(), hashlib.sha256).hexdigest() return hmac.compare_digest(expected, parts["v1"]) and abs(time.time() - int(parts["t"])) < 300
// PHP
[$t, $v1] = array_map(fn($p) => explode('=', $p, 2)[1], explode(',', $_SERVER['HTTP_X_VINTECHPAY_SIGNATURE']));
$raw = file_get_contents('php://input');
$ok = hash_equals(hash_hmac('sha256', "$t.$raw", $secret), $v1) && abs(time() - (int)$t) < 300;
4. Cek status & batalkan
GET https://payments.vintech.cloud/api/v1/orders/PAY-A1B2C3D4E5/ # status terkini POST https://payments.vintech.cloud/api/v1/orders/PAY-A1B2C3D4E5/cancel/ # hanya jika masih pending
Status: pending, paid, expired, cancelled.
Penting: parameter di return_url hanya informasi tampilan. Tandai pesanan lunas hanya berdasarkan webhook yang tervalidasi atau hasil GET order dari server Anda.
Kode error
Semua error berformat {"error": {"code": "...", "message": "..."}} dengan status 400 (permintaan tidak valid), 401 (API key salah), 404 (tidak ditemukan), 409 (konflik status).