callback
Endpoint
POST {{YourHost}}
Available Request Headers
| Key | Value |
|---|---|
| Content-Type | application/json |
Available Request Query Params
No Params
Available Request Body
No body defined.
Sample Request and Response
No samples found.
Documentation
Callback
Snapcart sends a POST request to the client’s registered callback URL when a transaction reaches (or reports) a terminal or intermediate status (Success / Failed / Pending — depending on implementation).
This document describes the body structure the client will RECEIVE (not an API you call). If you include a reference_id in your Inquiry/Payment request, Snapcart will echo it in callback payloads to help correlate with your internal orders.
Endpoint (Client Side)
POST https://{{YourHost}}
(You can customize the path; ensure it matches what was registered with Snapcart.)
Headers
| Header | Required | Description |
|---|---|---|
| Content-Type | Yes | application/json |
| (Optional Auth) | Conditional | HMAC/API key if agreed |
No query parameters.
Request Body Fields
| Field | Type | Length | Required | Description |
|---|---|---|---|---|
| request_id | string | 26 | Yes | Correlation ID for the transaction flow (Inquiry→Payment or one-step Payment). Use this as the primary key for status checks and idempotency. |
| reference_id | string | 1–100 | Optional | Client-supplied correlation ID. Echoed verbatim when sent in Inquiry/Payment; useful to join with your internal order/checkout. |
| product_code | string | 1–64 | Yes | Product code associated with the order. Derived from item_code in worker mapping. |
| bill_amount | number | - | Conditional | Total amount billed (multi-step BPJS/Postpaid) or amount paid (if available). May be 0.0 for pure validation (game voucher). |
| bill_number | string | 8–18 | Conditional | Billing / destination number for BPJS/Postpaid or prepaid products. Omitted for game voucher if not applicable. |
| status_code | string | - | Yes | Unified code (e.g. 200, 400, 402, 404, 500, etc.). |
| status_message | string | - | Yes | Unified message mapped from vendor/internal state (e.g. "Transaction successful", "Transaction failed"). |
| request_at | string | ISO8601 | Conditional | Original request timestamp (if propagated). May be empty if upstream did not include. |
| updated_at | string | ISO8601 | Yes | Final (or latest) update time when status was set internally. |
| additional_info | object | - | Optional | Product-specific enrichment; can be empty . Keys differ per product_code. |
Notes:
- There is currently NO dedicated error field in the callback body. Failure semantics are inferred from status_code / status_message.
- There is currently NO explicit order_status (SUCCESS/FAILED/PENDING) field — can be derived by client from status_code mapping.
- additional_info may be empty
{}and should be treated as optional. Never assume a fixed schema across products. - request_id is authoritative for Snapcart side tracing and Payment Status queries.
- reference_id is an optional client field echoed for your reconciliation.
About request_id vs reference_id
- request_id: generated by Snapcart; use for Payment Status, idempotency checks, and matching callbacks.
- reference_id: supplied by you; echoed in responses/callbacks when sent; use to join with your internal order or checkout IDs. Do not rely on it for API status queries (use request_id instead).
Product-Specific additional_info Keys
| Product Group / Example Code | Possible Keys (as sent) |
|---|---|
| BPJS Kesehatan VA (BPJS-KS) | customer_name, number_of_month, member_total, transaction_id |
| BPJS Ketenagakerjaan PU | bulan_tagihan, nama_perusahaan, kode_iuran |
| BPJS Ketenagakerjaan BPU | customer_name, bulan_periode, kantor_cabang, kode_iuran |
| BPJS KS Denda | customer_name, nama_perusahaan, jenis_tagihan, keterangan |
| Pulsa XL | customer_id, xl_prepaid_code, bill, period, pulsa, serial_number |
| Three Prepaid | customer_id, three_prepaid_code, bill, amount, serial_number, transaction_id |
| Smartfren Prepaid | customer_id, smartfren_prepaid_code, bill, window_period, amount, serial_number |
| Smartfren Paket Data (Mochan) | customer_id, smartfren_prepaid_code, bill, get_reff_no, amount, serial_number |
| Indosat Paket Data | customer_id, kode_paket, bill, window_period, amount, serial_number, trx_id |
| Indosat Prepaid | customer_id, product_code, bill, window_period, amount, serial_number, trx_id |
| Game Voucher (Generic) | invoice_id, reference, total_amount, sn, trx_date, callback_url, user_id, zone_id |
| PPOB generic (default mapping) | (often empty ) |
If a key is absent or empty, treat it as not provided — do not fail parsing.
Sample Callback Payloads (Success)
BPJS / Postpaid (Success)
{
"request_id": "01K9Y5K0YP9B1MPKCEVJCACZ3B",
"reference_id": "your-unique-id-2025-000123",
"product_code": "TELKOM_POSTPAID",
"bill_number": "081230000009",
"bill_amount": 5500,
"status_code": "200",
"status_message": "Transaction successful",
"request_at": "2025-11-21T03:40:05Z",
"updated_at": "2025-11-21T03:41:12Z",
"additional_info": {
"serial_number": "03357875092/112023/05/0003",
"idtrx": "01K9Y5K0YP9B1MPKCEVJCACZ3B",
"balance": "50.850"
}
}
BPJS Kesehatan VA
{
"request_id": "01HFAXYZABCDEF1234567890",
"reference_id": "your-unique-id-2025-000123",
"product_code": "BPJS-KS",
"bill_number": "888880000001234501",
"bill_amount": 105000.0,
"status_code": "200",
"status_message": "Transaction successful",
"request_at": "2025-11-21T02:12:10Z",
"updated_at": "2025-11-21T02:13:44Z",
"additional_info": {
"customer_name": "JOHN DOE",
"number_of_month": "1",
"member_total": "3",
"transaction_id": "TRX-BPJS-991122"
}
}
BPJS TK PU
{
"request_id": "01HFAXYZPUABCDEF123456789",
"reference_id": "your-unique-id-2025-000123",
"product_code": "BPJS-TK-PU",
"bill_number": "012345678901",
"bill_amount": 250000.0,
"status_code": "200",
"status_message": "Transaction successful",
"request_at": "2025-11-21T02:15:00Z",
"updated_at": "2025-11-21T02:16:05Z",
"additional_info": {
"bulan_tagihan": "202511",
"nama_perusahaan": "PT Sukses Abadi",
"kode_iuran": "IURAN-01"
}
}
BPJS TK BPU
{
"request_id": "01HFAXYZBPUABCDEF1234567",
"reference_id": "your-unique-id-2025-000123",
"product_code": "BPJS-TK-BPU",
"bill_number": "9876543210",
"bill_amount": 110000.0,
"status_code": "200",
"status_message": "Transaction successful",
"request_at": "2025-11-21T02:18:00Z",
"updated_at": "2025-11-21T02:19:02Z",
"additional_info": {
"customer_name": "ADI SAPUTRA",
"bulan_periode": "202511",
"kantor_cabang": "Jakarta Pusat",
"kode_iuran": "KDR-778"
}
}
BPJS KS Denda
{
"request_id": "01HFAXYZDENDA12345678901",
"reference_id": "your-unique-id-2025-000123",
"product_code": "BPJS-KS-DENDA",
"bill_number": "888880000009999999",
"bill_amount": 35000.0,
"status_code": "200",
"status_message": "Transaction successful",
"request_at": "2025-11-21T02:22:00Z",
"updated_at": "2025-11-21T02:23:11Z",
"additional_info": {
"customer_name": "SRI HANDAYANI",
"nama_perusahaan": "PT Prima",
"jenis_tagihan": "Denda",
"keterangan": "Late payment adjustment"
}
}
Pulsa XL Prepaid
{
"request_id": "01JK8HQJ2K1WMBBFGEV6CEH4WV",
"reference_id": "your-unique-id-2025-000123",
"product_code": "XL_FLEX_S_10",
"bill_number": "081230000042",
"bill_amount": 10000.0,
"status_code": "200",
"status_message": "Transaction successful",
"request_at": "2025-11-21T02:30:00Z",
"updated_at": "2025-11-21T02:30:20Z",
"additional_info": {
"customer_id": "081230000042",
"xl_prepaid_code": "FLEX-S-10",
"bill": "10000",
"period": "202511",
"pulsa": "10",
"serial_number": "SN-XL-88997766"
}
}
Three Prepaid
{
"request_id": "01JK8HQJ2K1WMBBFGEV6CEH4WZ",
"reference_id": "your-unique-id-2025-000123",
"product_code": "THREE_PREPAID",
"bill_number": "089912340001",
"bill_amount": 20000.0,
"status_code": "200",
"status_message": "Transaction successful",
"request_at": "2025-11-21T02:35:00Z",
"updated_at": "2025-11-21T02:35:19Z",
"additional_info": {
"customer_id": "089912340001",
"three_prepaid_code": "THR-20K",
"bill": "20000",
"amount": "20000",
"serial_number": "SN-3-112233",
"transaction_id": "TRX-3-8899"
}
}
Smartfren Prepaid
{
"request_id": "01JK8HQJ2K1WMBBFGEV6CEH500",
"reference_id": "your-unique-id-2025-000123",
"product_code": "SMARTFREN_PREPAID",
"bill_number": "088812345678",
"bill_amount": 15000.0,
"status_code": "200",
"status_message": "Transaction successful",
"request_at": "2025-11-21T02:40:00Z",
"updated_at": "2025-11-21T02:40:22Z",
"additional_info": {
"customer_id": "088812345678",
"smartfren_prepaid_code": "SF-15K",
"bill": "15000",
"window_period": "202511",
"amount": "15000",
"serial_number": "SN-SF-556677"
}
}
Smartfren Paket Data (Mochan)
{
"request_id": "01JK8HQJ2K1WMBBFGEV6CEH501",
"reference_id": "your-unique-id-2025-000123",
"product_code": "SMARTFREN_DATA_MOCHAN",
"bill_number": "088899991111",
"bill_amount": 60000.0,
"status_code": "200",
"status_message": "Transaction successful",
"request_at": "2025-11-21T02:42:00Z",
"updated_at": "2025-11-21T02:42:33Z",
"additional_info": {
"customer_id": "088899991111",
"smartfren_prepaid_code": "SF-DATA-60",
"bill": "60000",
"get_reff_no": "REF-778812",
"amount": "60000",
"serial_number": "SN-SF-DATA-123"
}
}
Indosat Paket Data
{
"request_id": "01JK8HQJ2K1WMBBFGEV6CEH502",
"reference_id": "your-unique-id-2025-000123",
"product_code": "INDOSAT_PAKET_DATA",
"bill_number": "085712345678",
"bill_amount": 50000.0,
"status_code": "200",
"status_message": "Transaction successful",
"request_at": "2025-11-21T02:45:00Z",
"updated_at": "2025-11-21T02:45:30Z",
"additional_info": {
"customer_id": "085712345678",
"kode_paket": "ID-PKT-50",
"bill": "50000",
"window_period": "202511",
"amount": "50000",
"serial_number": "SN-ID-1122",
"trx_id": "TRX-ID-9988"
}
}
Indosat Prepaid
{
"request_id": "01JK8HQJ2K1WMBBFGEV6CEH503",
"reference_id": "your-unique-id-2025-000123",
"product_code": "INDOSAT_PREPAID",
"bill_number": "085799991111",
"bill_amount": 25000.0,
"status_code": "200",
"status_message": "Transaction successful",
"request_at": "2025-11-21T02:48:00Z",
"updated_at": "2025-11-21T02:48:15Z",
"additional_info": {
"customer_id": "085799991111",
"product_code": "INDOSAT_PREPAID",
"bill": "25000",
"window_period": "202511",
"amount": "25000",
"serial_number": "SN-ID-P-2233",
"trx_id": "TRX-IP-2211"
}
}
Game Voucher
{
"request_id": "01JK8HQJ2K1WMBBFGEV6GAME01",
"reference_id": "your-unique-id-2025-000123",
"product_code": "ML-DIAMONDS-86",
"bill_amount": 0.0,
"status_code": "200",
"status_message": "Transaction successful",
"request_at": "2025-11-21T02:50:00Z",
"updated_at": "2025-11-21T02:50:19Z",
"additional_info": {
"invoice_id": "INV-ML-5566",
"reference": "REF-998877",
"total_amount": "15000",
"sn": "SERIAL-ML-112233",
"trx_date": "2025-11-21T02:50:15Z",
"callback_url": "https://client.example.com/callback",
"user_id": "Player123",
"zone_id": "SEA"
}
}
Generic PPOB (Empty additional_info)
{
"request_id": "01JK8HQJ2K1WMBBFGEV6PPOB01",
"reference_id": "your-unique-id-2025-000123",
"product_code": "PPOB-ELECTRIC",
"bill_number": "012345678000",
"bill_amount": 112500.0,
"status_code": "200",
"status_message": "Transaction successful",
"request_at": "2025-11-21T02:55:00Z",
"updated_at": "2025-11-21T02:55:35Z",
"additional_info": {}
}
Pending Callback Example
(If system emits a pending state; some deployments only send terminal states.)
{
"request_id": "01JK8HQJ2K1WMBBFGEV6CEH4WV",
"reference_id": "your-unique-id-2025-000123",
"product_code": "XL_FLEX_S_10",
"bill_number": "081230000042",
"bill_amount": 10000.0,
"status_code": "200",
"status_message": "Transaction is being processed",
"request_at": "2025-11-21T03:00:00Z",
"updated_at": "2025-11-21T03:00:04Z",
"additional_info": {
"customer_id": "081230000042",
"xl_prepaid_code": "FLEX-S-10"
}
}
Failure Examples
Incorrect Bill Number (BPJS/Postpaid)
{
"request_id": "01HFAXYZABCDEF1234567890",
"reference_id": "your-unique-id-2025-000123",
"product_code": "TELKOM_POSTPAID",
"bill_number": "081230000009",
"bill_amount": 0.0,
"status_code": "400",
"status_message": "Incorrect bill number",
"request_at": "2025-11-21T02:10:10Z",
"updated_at": "2025-11-21T02:10:22Z",
"additional_info": {}
}
Insufficient Balance (After Inquiry)
{
"request_id": "01K9Y5K0YP9B1MPKCEVJCACZ3B",
"reference_id": "your-unique-id-2025-000123",
"product_code": "TELKOM_POSTPAID",
"bill_number": "081230000009",
"bill_amount": 5500,
"status_code": "402",
"status_message": "Insufficient balance",
"request_at": "2025-11-21T03:10:05Z",
"updated_at": "2025-11-21T03:10:05Z",
"additional_info": {
"serial_number": "03357875092/112023/05/0003"
}
}
Transaction Failed (Vendor Failure)
{
"request_id": "01JK8HQJ2K1WMBBFGEV6FAIL01",
"reference_id": "your-unique-id-2025-000123",
"product_code": "XL_FLEX_S_10",
"bill_number": "081230000042",
"bill_amount": 10000.0,
"status_code": "400",
"status_message": "Transaction failed",
"request_at": "2025-11-21T03:12:00Z",
"updated_at": "2025-11-21T03:12:40Z",
"additional_info": {
"customer_id": "081230000042",
"xl_prepaid_code": "FLEX-S-10"
}
}
Transaction Not Found
{
"request_id": "01JK8H_UNKNOWN_REQUEST_ID",
"reference_id": "",
"product_code": "ML-DIAMONDS-86",
"bill_amount": 0.0,
"status_code": "404",
"status_message": "Transaction not found",
"request_at": "",
"updated_at": "2025-11-21T03:20:10Z",
"additional_info": {}
}
Inquiry Expired (Two-Step)
{
"request_id": "01HFAXYZABCDEF1234567890",
"reference_id": "your-unique-id-2025-000123",
"product_code": "BPJS-KS",
"bill_number": "888880000001234501",
"bill_amount": 105000.0,
"status_code": "410",
"status_message": "Inquiry expired",
"request_at": "2025-11-21T02:00:00Z",
"updated_at": "2025-11-21T02:30:05Z",
"additional_info": {
"customer_name": "JOHN DOE",
"number_of_month": "1"
}
}
Third Party Error (Vendor)
{
"request_id": "01JK8HQJ2K1WMBBFGEV6ERR500",
"reference_id": "your-unique-id-2025-000123",
"product_code": "INDOSAT_PREPAID",
"bill_number": "085799991111",
"bill_amount": 25000.0,
"status_code": "500",
"status_message": "Third party error",
"request_at": "2025-11-21T03:25:00Z",
"updated_at": "2025-11-21T03:25:11Z",
"additional_info": {
"customer_id": "085799991111",
"product_code": "INDOSAT_PREPAID"
}
}
Idempotency & Handling
| Concern | Guidance |
|---|---|
| Duplicate callback | Treat as idempotent: check request_id; ignore repeats after first persistence. Optionally also match on reference_id if you send it. |
| Missing optional keys | Safely ignore; never hard fail parsing. |
| Empty additional_info | Accept as valid; may occur for products with no enrichment. |
| Unknown status_code | Fallback to generic error handling; escalate with raw payload. |
| Out-of-order arrival | Always rely on updated_at; store latest and discard older timestamps for same request_id. |
Recommended Client Processing Flow
- Receive POST
- Validate JSON structure & mandatory fields (request_id, product_code, status_code, status_message).
- Persist record (audit log + transactional save), joining with your order using reference_id if present.
- Apply business classification (Success / Pending / Failed) based on status_code.
- If status_code indicates Pending, continue polling Payment Status API (if implemented).
- If success/failure terminal: stop polling & finalize settlement logic.
- Emit internal event / notify downstream systems.
Mapping Terminal vs Non-Terminal (Suggested)
| status_code | status_message | Terminal? | Notes |
|---|---|---|---|
| 200 + “Transaction successful” | Success | Yes | Final success. |
| 200 + “Transaction is being processed” | Pending | No | Continue polling. |
| 402 | Insufficient balance | Yes | Failed due to balance; requires top-up then new flow. |
| 400 / 404 / 410 | Various failures | Yes | Terminal; analyze cause & possibly restart flow. |
| 500+ | Third party / internal errors | Yes (usually) | Investigate; may allow re-initiation with new request_id. |
Additional Info Variability
- Treat all additional_info keys as optional.
- Do not rely on one product’s keys existing in another product.
- Unknown keys should be preserved for logging but safely ignored in core logic.
Next Step After Receiving Callback
- If terminal: update transaction state & stop polling.
- If pending: continue periodic GET /pre-order/payment/status/:request_id until terminal.
- For failures like Insufficient balance (402): instruct wallet top-up before new Payment.
- For Inquiry expired (410): restart from Inquiry.
Notes
- This format reflects current implementation.
- Any schema evolution should remain backward-compatible; clients should ignore unknown fields (forward compatibility).