Part 2
Data formats, idempotency, and errors
Data types, pagination, safe retries with Idempotency-Key, and error codes.
Data types
| Element | v1 contract |
|---|---|
| Amount | A string of whole-rupiah digits, e.g. "100000". No dots, commas, "Rp" sign, or decimals. Must be positive and within the channel limit. |
| Currency | IDR. Fields with unsupported values are rejected. |
| IDs and references | AntaraPay IDs are opaque strings. A merchant reference is 1–64 characters of A–Z, a–z, 0–9, dot, underscore, or hyphen; unique per operation type. |
| Time | RFC 3339 UTC, e.g. 2026-10-15T05:00:00Z. The from filter is inclusive and to is exclusive. |
| Metadata | Optional object, at most 10 keys with string values; at most 2 KB of JSON. Avoid sensitive data. |
| Pagination | limit defaults to 50, maximum 200; cursor is opaque. Lists are newest first, except the journal which is ordered by ascending sequence. |
| Response | Success uses data and request_id. Lists add pagination.next_cursor and has_more. null means the value is not available yet. |
{
"data": [ ... ],
"pagination": { "next_cursor": "opaque_cursor", "has_more": true },
"request_id": "req_example"
}Safe retries
Use a key of 1–128 characters for one POST. The same key with the same body returns the same resource; a different body returns 409 IDEMPOTENCY_CONFLICT. The reference stays unique even with a new key. Do not create a new reference when a response times out. Retry with the same key and body, or look the resource up by reference.
Idempotency responses are designed to be retained for 7 days; financial references cannot be reused for as long as the transaction record is kept. A request that fails authentication or validation has not created a resource. An accepted replay returns the same ID; use GET for the latest status.
Recommended retry pattern
Idempotency-Key with your order record before sending the request. On a timeout, resend with exactly the same key and body, or look the resource up by reference.Error format and codes
{
"error": {
"code": "INSUFFICIENT_BALANCE",
"message": "Saldo available tidak mencukupi.",
"retryable": false
},
"request_id": "req_example"
}| HTTP | Code | Client action |
|---|---|---|
| 400 / 422 | VALIDATION_ERROR | Fix the payload; read message. |
| 401 / 403 | UNAUTHORIZED / FORBIDDEN | Check the key and scope. |
| 404 | NOT_FOUND | Check the ID and environment. |
| 409 | IDEMPOTENCY_CONFLICT / REFERENCE_EXISTS | Use the original request or read the existing resource. |
| 409 | INSUFFICIENT_BALANCE / INVALID_STATE | Check the balance or the latest status. |
| 429 | RATE_LIMITED | Follow Retry-After (seconds). |
| 500 / 503 | INTERNAL_ERROR / CHANNEL_UNAVAILABLE | Retry with backoff and the same key; check the status if the outcome is unclear. |
The message text is a human-readable description (the example above is in Indonesian, as in the source contract); rely on code in your logic.
QR-specific errors
The QR image endpoint returns JSON errors: 409 QR_NOT_READY, 409 INVALID_STATE, 410 QR_EXPIRED, or 422 CHANNEL_NOT_QR. See the Payin section.