Skip to main content

Appendix – Response Codes & Messages

This appendix focuses ONLY on the unified response codes (status_code) and messages (status_message) you will receive from Snapcart PPOB & Game Voucher APIs (Inquiry, Payment, Payment Status, Catalog endpoints, and Callbacks).

Use this as a quick reference for:

  • Determining whether a transaction is final or still in progress.
  • Showing user‑friendly status.
  • Deciding next action (retry, stop, prompt user).

Standard Response Envelope

Successful or error responses follow:

{
"status_code": "200",
"status_message": "Transaction successful",
"data": { ... },
"error": ""
}

Field rules:

  • status_code: Always a string, Unified code (e.g. "200", "400").
  • status_message: Human-readable, High-level status description.
  • data: Object or array; may be omitted on certain failures.
  • error: Present and non-empty only when there is a client/input/system/biller error.

IDs and correlation:

  • request_id: Snapcart‑generated; use for Payment Status queries and callback matching.
  • reference_id: Client‑supplied; echoed verbatim when sent in Inquiry/Payment; store alongside request_id for reconciliation.

Ignore unknown future fields (forward compatibility).


Status Classification Cheat Sheet

ClassificationMeaningExamples (status_code + status_message)
Final SuccessTransaction completed successfully200 + Transaction successful
Final FailureWill not recover; start a new flow or inform user400 Transaction failed, 402 Insufficient balance, 404 Product not found, 410 Inquiry expired, 500 Third party error
In ProgressStill processing; poll or await callback200 Transaction is being processed
Action RequiredClient must do something before continuing402 Insufficient balance (top-up), 202 Waiting for payment (perform payment)

Unified Response Codes & Messages

status_codestatus_messageClassificationTypical WhenClient Action
200Transaction successfulFinal SuccessInquiry (bill OK), Payment status final, CallbackStop polling; mark success
200Transaction is being processedIn ProgressPayment acknowledged / vendor processingPoll or await callback
202Waiting for paymentIn ProgressTwo-step products after inquiry (before payment)Execute Payment before expiry
400Bad requestFinal FailureMissing/invalid JSON / fieldsFix request & retry
400Transaction failedFinal FailureVendor processed & failedShow failure; allow new attempt
400Incorrect bill numberFinal FailureInvalid destination/account numberPrompt user to re-enter
400Product and number mismatchFinal FailureWrong product for destination (e.g. phone number prefix mismatch)Let user choose correct product
401UnauthorizedFinal FailureInvalid/missing API keyCorrect API key configuration
403Invalid IP addressFinal FailureIP not registered/blockedRegister or fix client IP
403Client InactiveFinal FailureClient/API key disabledContact support / reactivate
402Insufficient balanceFinal Failure (requires new flow)Wallet < required amountTop-up then start new inquiry/payment
404Product not foundFinal FailureUnknown/inactive product_code/item_codeRefresh catalog / correct code
404Transaction not foundFinal FailureInvalid request_id in Payment StatusVerify ID / use correct reference
404Vendor not foundFinal FailureNo vendor mapped for productContact support / configuration fix
409Product out of stockFinal FailureInventory/quota depletedHide option; suggest alternative
409Bill already paidFinal FailureDuplicate bill payment attemptInform user; stop
409Outstanding billFinal FailurePostpaid/BPJS arrears presentPrompt to settle arrears first
410Inquiry expiredFinal FailurePayment performed after inquiry TTLRestart from Inquiry
429Too many requests, please try again laterFinal Failure (retry after wait)Rate limit exceeded (polling too fast)Backoff & retry later
500Third party errorFinal FailureUnmapped vendor issue / generic fallbackRetry new flow (limited attempts)
500Configuration errorFinal FailureMissing route/product mapping internalContact support
500Database errorFinal FailureInternal persistence failureRetry new flow / escalate if persistent
502General errorFinal FailureGateway / intermediate failureRetry new flow
503System maintenanceFinal FailureMaintenance windowRetry after maintenance
408Request timeoutIn Progress / TransitionalInternal operation timeout (rare surface)Poll again; escalate if persistent

Note: All codes are strings. Treat unknown (future) status_message values conservatively: if status_code != "200" or the message is not clearly success, handle as failure/in‑progress according to the numeric code.


Client Actions Cheat Sheet

ScenarioAction
Processing persists beyond SLAEscalate / show delayed message
Insufficient balance (402)Prompt top-up, restart fresh inquiry/payment
Inquiry expired (410)Restart Inquiry → Payment flow
Rate limited (429)Increase poll interval / exponential backoff
Vendor/system error (500/502/503)Limited retries (e.g., 1–2) then fail
Product out of stock (409)Remove option; suggest alternative
Incorrect bill number (400)Prompt user to correct destination
Transaction not found (404)Verify request_id; if wrong discard

Callback vs Polling

  • If callback returns a final status, stop polling immediately.
  • If callback returns an in‑progress status (rare), continue polling until final.
  • Always trust the latest updated_at (if provided) or treat any final status as authoritative.
  • Strongly recommended: rely on callback alone for production (minimal polling) to reduce load and latency; use polling only as a fallback or during initial integration/testing.