Errors & conventions
Error shape
Errors are JSON:
{ "error": "Human-readable message" }
Some proxied or provider-adjacent responses use message, details, or raw instead. Resolve a display message in this order: error → message → raw → HTTP status text. Some not-found reads return a bodyless 204 No Content — tolerate it.
HTTP status codes
| Code | Meaning | Typical causes |
|---|---|---|
200 / 201 |
Success | 201 on resource creation. |
204 |
No content | Some not-found reads. |
400 |
Bad request | Missing/invalid fields, snapshot mismatch, currency mismatch, invalid signature payload, Octopus increment violation, attempts to change immutable fields. |
401 |
Unauthenticated | Missing API key header. |
403 |
Forbidden | Invalid key, out-of-scope merchant/store/resource, disabled payment network, forbidden write (e.g. setting an intent to S, product writes). |
404 |
Not found | Resource absent or not visible in your scope. |
409 |
Conflict | KYB gate (API key before approval), conflicting or terminal checkout launch, duplicate unique values. |
500 |
Server error | Report with timestamp + request path. |
502 |
Upstream error | Payment-gateway or internal service failure; safe to retry idempotent reads. |
Client guidance: treat 4xx as "fix the request" (don't blind-retry), 502 on reads as retryable with backoff, and callback forwards (record_payment, recurring/*/record) as always safe to retry — they're idempotent.
Idempotency & retries
There is no idempotency-key header; idempotency is built into the money-moving endpoints themselves:
| Endpoint | Retry behavior |
|---|---|
POST /pa/checkout |
One signed launch per intent. An identical retry returns the stored response; a conflicting or terminal checkout returns 409. |
POST /paymentasia/record_payment |
Exact replays return the recorded result with "idempotent": true. Forward duplicates freely. |
POST /recurring/tokenization/record, POST /recurring/payment/record |
Same replay semantics as record_payment. |
POST /intent (create) |
Not idempotent — a retry after a network timeout creates a second intent. Use your unique reference (merchant reference) to detect and discard duplicates on your side. |
All GETs |
Safe to retry with backoff. |
Pagination
List endpoints return the full scoped result set as a JSON array — there is no cursor or page parameter. Keep result sets bounded with the documented filters (identifier, status, created_from / created_to, order_id, …), especially on intents, orders, and payments reconciliation sweeps.
Data conventions
| Convention | Rule |
|---|---|
| Money | Fixed-point decimal strings with 2 decimals ("300.00"). Never compute money in binary floating point. |
| Currency | 3 uppercase letters (HKD). One currency per checkout. |
| IDs | Numeric id = internal integer key (route paths, foreign keys). identifier = public UUID-like string (≤ 36 chars). A checkout ID is an intent's identifier. |
| Merchant reference | Your unique-per-checkout reference: globally unique, ≤ 36 characters. UUID4 recommended. |
| Timestamps | Server-formatted date/time strings; parse leniently. Range filters accept ISO-8601 (created_from inclusive, created_to exclusive). |
| Headers | Auth via the three X-PingBiz-* headers on every call; never in query strings. |
Status letters
Intent (checkout) status
| Letter | Meaning | Terminal |
|---|---|---|
C |
Created | No |
R |
Redirected to gateway / processing | No |
S |
Succeeded (verified) | Yes |
F |
Failed (verified) | Yes |
U |
Unknown — reconcile | Yes (for UI) |
Order status — single letters; the set includes N, P, C, R, S, F, U. Orders you receive from checkout success are payment-complete; use order status for display and ops filtering.
Payment status — S = successful. Payments are only written after verification, so this is the value you'll see.
Order item state — D = delivered, null = not marked delivered (delivery marking happens in the Merchant Portal / back office, not via this API).
Store mode — T = test, L = live.
Product state — A = approved/purchasable.
Recurring status — PENDING, ACTIVE, CANCELLED, COMPLETED, ERROR, UNKNOWN (subscriptions).
Merchant KYB status — in_review, approved, rejected (getting started).