· API Docs
v1.0.0OAS 3.1.0

p2p Payment Gateway — Public API

Download OpenAPI Document

The public /v1 API is for merchant server-to-server integration. Every request is authenticated with a secret API key (Authorization: Bearer sk_test_... or sk_live_...), gated by a per-merchant IP allowlist, and rate limited. HMAC request signing is an optional, additive gate for API keys in either environment. When signing is enabled for a key, every request made with that key must also send X-Signature-Timestamp and X-Signature; signing never replaces Bearer authentication, the IP allowlist, rate limiting, or mandatory idempotency. The key prefix selects the server-owned financial environment. Financial resources and idempotency are isolated by environment; shared merchant resources are called out on their operations. All money is an integer number of the named currency's minor units, serialized as JSON numbers, never floats. Currency metadata and operation readiness are server-owned; balances and every aggregate stay isolated by currency and the gateway performs no implicit FX. Every POST request requires an Idempotency-Key header. This is a separate surface from the dashboard /api tree, which uses cookie sessions; the two never share credentials.

Payins

Inbound payments — money a customer sends to you.

GET/v1/payins

List payins

Newest first. Scope payins:read. data is a bare array of PayinView. Prefer cursor + limit for high-volume paging; offset remains for small pages.

Query parameters

limitintegerquery

Page size.

offsetintegerquery

Records to skip for pagination.

cursorstringquery

Stable keyset cursor from the previous page's last row: {RFC3339}_{uuid} built from that row's created_at and id. Mutually exclusive with a non-zero offset. Ordering is (created_at DESC, id DESC).

statusenum (pending | success | expired | cancelled | failed)query
currencystringquery
qstringquery

Headers

X-Signaturestringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send the lowercase hexadecimal HMAC-SHA256 of METHOD\nPATH_AND_QUERY\nTIMESTAMP\nIDEMPOTENCY_KEY\nBODY using the reusable hs_... signing secret revealed once. METHOD is the exact method token sent. PATH_AND_QUERY is the exact raw, already-encoded path and query received by the server; do not decode, normalize, or sort it. IDEMPOTENCY_KEY is the exact header value, or an empty string when absent. BODY is the raw request body bytes, or empty bytes when absent.

X-Signature-Timestampstringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send canonical base-10 Unix seconds within ±300 seconds of server time and sign the same value. For a retry of the same logical operation, reuse the original Idempotency-Key but create a fresh timestamp and signature.

Responses

200A bare array of payins, wrapped in the ApiResponse envelope.
401Bad credentials or request signing — missing/malformed Authorization header, unknown key, key not in status `active`, or a missing, invalid, or stale HMAC signature for a key that has signing enabled.
403Key lacks the required scope, or the client IP is not in the merchant allowlist.
429Per-key rate limit exceeded — back off and retry.
POST/v1/payins

Create a payin

Create an inbound payment request in the API key's environment. Scope payins:write. Idempotent: an Idempotency-Key header is required. order_ref must be unique per merchant and environment; the same value may be used independently in test and live. When receiving_type is p2p and direct matching dispatch is enabled, admission claims a pending P2P payout with the same currency and gross amount; if none is available, or matching is off, the payin is admitted on a fallback collection rail in the operator-configured order (System settings, P2P tab: bank transfer then QR by default, QR then bank, or off). The request fails with 422 (P2P_LIQUIDITY_UNAVAILABLE) only when fallback is off or no collection rail can accept it. Channel: channel selects the rail — bank (the default when omitted), qrcode, or crypto — as a shortcut for provider/receiving_type; when set it overrides them. bank and qrcode return a PayinView with a hosted-pay pay_token. crypto instead opens a per-transaction USDT deposit and returns a deposit address on a network (no pay_token); send network (for example TRC20) or omit it to use the operator default network. For crypto, amount is µUSDT and currency is ignored. The channels and crypto networks that are accepted follow the operator's System settings (the payment-method switches and the enabled crypto network set); a channel or network the operator has disabled is rejected with 422.

Headers

X-Signaturestringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send the lowercase hexadecimal HMAC-SHA256 of METHOD\nPATH_AND_QUERY\nTIMESTAMP\nIDEMPOTENCY_KEY\nBODY using the reusable hs_... signing secret revealed once. METHOD is the exact method token sent. PATH_AND_QUERY is the exact raw, already-encoded path and query received by the server; do not decode, normalize, or sort it. IDEMPOTENCY_KEY is the exact header value, or an empty string when absent. BODY is the raw request body bytes, or empty bytes when absent.

X-Signature-Timestampstringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send canonical base-10 Unix seconds within ±300 seconds of server time and sign the same value. For a retry of the same logical operation, reuse the original Idempotency-Key but create a fresh timestamp and signature.

Idempotency-Keystringheaderrequired

Opaque unique value for one logical operation. UUID v7 is recommended for new values but not required; reuse the same key for every retry. The namespace is (merchant, environment, key), so the same value may be used independently in test and live. Request identity is SHA256(POST + "\n" + ROUTE_PATH + "\n" + RAW_BODY): ROUTE_PATH is the already-encoded route path visible to the /v1 router after Axum strips the /v1 mount prefix (for example, client path /v1/payins hashes /payins); query excluded; do not decode, normalize, or sort. The raw body is the exact request body bytes (do not parse or reserialize). This layer applies only to POST; other methods bypass it. Same key + same route path and raw body replays the original 2xx response with header idempotent-replay: true. Same key + different route path or raw body → 409.

Body (PayinCreate)

order_refstringrequired

Your unique reference for this payment. Unique per merchant and environment; a duplicate in the same environment is a 409.

amountinteger (int64)required
currencystring

Defaults to THB. Live creation succeeds only when the requested currency is active, the merchant has an explicit fee profile, and an enabled collection account exists for the requested currency/provider; the initial live manual-slip rollout is THB. Sandbox creation can exercise other active catalog currencies without exposing a live collection destination.

providerstring

Payin provider. manual_slip is the currently implemented provider; live admission also requires an enabled merchant/currency/provider collection account.

receiving_typeenum (p2p | bank_transfer | qr)
channelenum (bank | qrcode | crypto)

Selects the payment rail as a shortcut for provider/receiving_type; when set it overrides them. bank (the default when omitted) is a bank transfer and qrcode (alias qr) is a PromptPay QR — both return a PayinView with a hosted-pay pay_token. crypto instead opens a per-transaction USDT deposit and returns a deposit address on a network (no pay_token). The channels that are accepted follow the operator's System settings; a disabled channel is rejected with 422.

networkenum (TRC20 | SOLANA | BEP20 | ERC20 | )

Crypto network for channel = crypto (TRC20, SOLANA, BEP20, or ERC20); ignored for other channels. Omit it to use the operator's default network. Must be one of the operator's enabled networks, otherwise the request is a 422. For crypto, amount is µUSDT and currency is ignored.

client_operation_idstring,null (uuid)

Optional client-side operation UUID for extra dedupe. UUID v7 is recommended for new values; historical UUID versions already stored are still accepted on read.

counterparty_account_idstring,null (uuid)

Optional counterparty account in the API key's environment this payin is expected from. The sandbox hosted-pay surface never exposes a live collection destination.

redirect_urlstring,null (uri)

Optional HTTPS redirect after hosted-pay success or expiry.

pay_themeenum (classic | light | dark | breeze | linen | royal | grid | coral | onyx | aurora | terra | leaf | neon | forest-green | choco-cosmos | uefa | smoky-black | safety-orange | deep-green | purple-dark | pink | blue-dark | lime-green | sky-fun | modern | modern-blue | modern-teal | modern-emerald | modern-violet | modern-rose | modern-amber | modern-slate | )

Optional hosted-pay theme.

notesstring,null

Optional merchant memo.

Responses

200The payin, wrapped in the ApiResponse envelope.
400Malformed request identity or amount — including an unknown/inactive currency for new admission, non-positive or unit-step-misaligned money, an invalid fee split, or malformed customer fields.
401Bad credentials or request signing — missing/malformed Authorization header, unknown key, key not in status `active`, or a missing, invalid, or stale HMAC signature for a key that has signing enabled.
403Key lacks the required scope, or the client IP is not in the merchant allowlist.
409Idempotency-Key reused for a different request identity (route path or raw request body), a request already in progress, or a duplicate order_ref.
422A structurally known request cannot run now — for example the exact live payin collection rail is not enabled, a destination is inactive/unverified for the operation, the same-currency available balance is insufficient (including an empty settlement sweep), or no matching P2P payout liquidity and no collection-rail fallback is available for a direct P2P payin (`P2P_LIQUIDITY_UNAVAILABLE`).
429Per-key rate limit exceeded — back off and retry.
GET/v1/payins/{id}

Get a payin

Scope payins:read. Returns the payin, or 404 if the id is unknown or belongs to another merchant.

Path parameters

idstring (uuid)pathrequired

Payin UUID.

Headers

X-Signaturestringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send the lowercase hexadecimal HMAC-SHA256 of METHOD\nPATH_AND_QUERY\nTIMESTAMP\nIDEMPOTENCY_KEY\nBODY using the reusable hs_... signing secret revealed once. METHOD is the exact method token sent. PATH_AND_QUERY is the exact raw, already-encoded path and query received by the server; do not decode, normalize, or sort it. IDEMPOTENCY_KEY is the exact header value, or an empty string when absent. BODY is the raw request body bytes, or empty bytes when absent.

X-Signature-Timestampstringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send canonical base-10 Unix seconds within ±300 seconds of server time and sign the same value. For a retry of the same logical operation, reuse the original Idempotency-Key but create a fresh timestamp and signature.

Responses

200The payin, wrapped in the ApiResponse envelope.
401Bad credentials or request signing — missing/malformed Authorization header, unknown key, key not in status `active`, or a missing, invalid, or stale HMAC signature for a key that has signing enabled.
403Key lacks the required scope, or the client IP is not in the merchant allowlist.
404The id is unknown or belongs to another merchant; environment-scoped routes also use 404 without disclosing an object from the other environment.
429Per-key rate limit exceeded — back off and retry.
POST/v1/payins/{id}/cancel

Cancel a payin

Scope payins:write. Idempotent (Idempotency-Key required). Allowed only while the payin is pending; cancelling anything else is a 409 Conflict.

Path parameters

idstring (uuid)pathrequired

Payin UUID.

Headers

X-Signaturestringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send the lowercase hexadecimal HMAC-SHA256 of METHOD\nPATH_AND_QUERY\nTIMESTAMP\nIDEMPOTENCY_KEY\nBODY using the reusable hs_... signing secret revealed once. METHOD is the exact method token sent. PATH_AND_QUERY is the exact raw, already-encoded path and query received by the server; do not decode, normalize, or sort it. IDEMPOTENCY_KEY is the exact header value, or an empty string when absent. BODY is the raw request body bytes, or empty bytes when absent.

X-Signature-Timestampstringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send canonical base-10 Unix seconds within ±300 seconds of server time and sign the same value. For a retry of the same logical operation, reuse the original Idempotency-Key but create a fresh timestamp and signature.

Idempotency-Keystringheaderrequired

Opaque unique value for one logical operation. UUID v7 is recommended for new values but not required; reuse the same key for every retry. The namespace is (merchant, environment, key), so the same value may be used independently in test and live. Request identity is SHA256(POST + "\n" + ROUTE_PATH + "\n" + RAW_BODY): ROUTE_PATH is the already-encoded route path visible to the /v1 router after Axum strips the /v1 mount prefix (for example, client path /v1/payins hashes /payins); query excluded; do not decode, normalize, or sort. The raw body is the exact request body bytes (do not parse or reserialize). This layer applies only to POST; other methods bypass it. Same key + same route path and raw body replays the original 2xx response with header idempotent-replay: true. Same key + different route path or raw body → 409.

Responses

200The payin, wrapped in the ApiResponse envelope.
401Bad credentials or request signing — missing/malformed Authorization header, unknown key, key not in status `active`, or a missing, invalid, or stale HMAC signature for a key that has signing enabled.
403Key lacks the required scope, or the client IP is not in the merchant allowlist.
404The id is unknown or belongs to another merchant; environment-scoped routes also use 404 without disclosing an object from the other environment.
409Idempotency-Key reused for a different request identity (route path or raw request body), a request already in progress, or a duplicate order_ref.
429Per-key rate limit exceeded — back off and retry.
POST/v1/payins/{id}/test-confirm

Confirm a sandbox payin

Sandbox simulator for integration tests. Scope payins:write; the calling key and target payin must both be test. Requires Idempotency-Key. Transitions a pending test payin to success, emits a webhook with livemode: false, and never credits a balance or calls a live provider. A live key is rejected with 403; an object from the other environment is not disclosed.

Path parameters

idstring (uuid)pathrequired

Payin UUID.

Headers

X-Signaturestringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send the lowercase hexadecimal HMAC-SHA256 of METHOD\nPATH_AND_QUERY\nTIMESTAMP\nIDEMPOTENCY_KEY\nBODY using the reusable hs_... signing secret revealed once. METHOD is the exact method token sent. PATH_AND_QUERY is the exact raw, already-encoded path and query received by the server; do not decode, normalize, or sort it. IDEMPOTENCY_KEY is the exact header value, or an empty string when absent. BODY is the raw request body bytes, or empty bytes when absent.

X-Signature-Timestampstringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send canonical base-10 Unix seconds within ±300 seconds of server time and sign the same value. For a retry of the same logical operation, reuse the original Idempotency-Key but create a fresh timestamp and signature.

Idempotency-Keystringheaderrequired

Opaque unique value for one logical operation. UUID v7 is recommended for new values but not required; reuse the same key for every retry. The namespace is (merchant, environment, key), so the same value may be used independently in test and live. Request identity is SHA256(POST + "\n" + ROUTE_PATH + "\n" + RAW_BODY): ROUTE_PATH is the already-encoded route path visible to the /v1 router after Axum strips the /v1 mount prefix (for example, client path /v1/payins hashes /payins); query excluded; do not decode, normalize, or sort. The raw body is the exact request body bytes (do not parse or reserialize). This layer applies only to POST; other methods bypass it. Same key + same route path and raw body replays the original 2xx response with header idempotent-replay: true. Same key + different route path or raw body → 409.

Responses

200The payin, wrapped in the ApiResponse envelope.
401Bad credentials or request signing — missing/malformed Authorization header, unknown key, key not in status `active`, or a missing, invalid, or stale HMAC signature for a key that has signing enabled.
403Key lacks the required scope, or the client IP is not in the merchant allowlist.
404The id is unknown or belongs to another merchant; environment-scoped routes also use 404 without disclosing an object from the other environment.
409Idempotency-Key reused for a different request identity (route path or raw request body), a request already in progress, or a duplicate order_ref.
429Per-key rate limit exceeded — back off and retry.
POST/v1/slip/verify

Verify a bank transfer slip from QR data

Live-only lookup of a Thai bank slip from the QR payload printed on the transfer receipt. Scope slip:verify. Idempotent: an Idempotency-Key header is required; reuse the same key for every retry. Only sk_live_ keys may reach the shared production cache or configured upstream provider; sk_test_ is rejected with 403 before either path. A cache hit within 24h does not call the upstream provider. data.success is the business outcome — HTTP 200 is returned for both verified and rejected slips. Amounts are integer minor units (satang for THB). This endpoint does not credit a payin or move money.

Headers

X-Signaturestringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send the lowercase hexadecimal HMAC-SHA256 of METHOD\nPATH_AND_QUERY\nTIMESTAMP\nIDEMPOTENCY_KEY\nBODY using the reusable hs_... signing secret revealed once. METHOD is the exact method token sent. PATH_AND_QUERY is the exact raw, already-encoded path and query received by the server; do not decode, normalize, or sort it. IDEMPOTENCY_KEY is the exact header value, or an empty string when absent. BODY is the raw request body bytes, or empty bytes when absent.

X-Signature-Timestampstringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send canonical base-10 Unix seconds within ±300 seconds of server time and sign the same value. For a retry of the same logical operation, reuse the original Idempotency-Key but create a fresh timestamp and signature.

Idempotency-Keystringheaderrequired

Opaque unique value for one logical operation. UUID v7 is recommended for new values but not required; reuse the same key for every retry. The namespace is (merchant, environment, key), so the same value may be used independently in test and live. Request identity is SHA256(POST + "\n" + ROUTE_PATH + "\n" + RAW_BODY): ROUTE_PATH is the already-encoded route path visible to the /v1 router after Axum strips the /v1 mount prefix (for example, client path /v1/payins hashes /payins); query excluded; do not decode, normalize, or sort. The raw body is the exact request body bytes (do not parse or reserialize). This layer applies only to POST; other methods bypass it. Same key + same route path and raw body replays the original 2xx response with header idempotent-replay: true. Same key + different route path or raw body → 409.

Body (SlipVerifyRequest)

qr_datastringrequired

QR payload from a Thai bank transfer slip.

Responses

200Slip QR verification result. `data.success` is the business outcome.
401Bad credentials or request signing — missing/malformed Authorization header, unknown key, key not in status `active`, or a missing, invalid, or stale HMAC signature for a key that has signing enabled.
403Key lacks the required scope, or the client IP is not in the merchant allowlist.
429Per-key rate limit exceeded — back off and retry.
503Slip verification is disabled on this deployment.
GET/v1/slip/verify/{ref}

Lookup a cached slip verification by transaction reference

Returns the most recent cached slip verification for a provider transaction reference. Scope slip:verify. Live-only (sk_test_ → 403). Does not call the upstream provider.

Path parameters

refstringpathrequired

Provider transaction reference from a prior successful slip verification.

Headers

X-Signaturestringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send the lowercase hexadecimal HMAC-SHA256 of METHOD\nPATH_AND_QUERY\nTIMESTAMP\nIDEMPOTENCY_KEY\nBODY using the reusable hs_... signing secret revealed once. METHOD is the exact method token sent. PATH_AND_QUERY is the exact raw, already-encoded path and query received by the server; do not decode, normalize, or sort it. IDEMPOTENCY_KEY is the exact header value, or an empty string when absent. BODY is the raw request body bytes, or empty bytes when absent.

X-Signature-Timestampstringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send canonical base-10 Unix seconds within ±300 seconds of server time and sign the same value. For a retry of the same logical operation, reuse the original Idempotency-Key but create a fresh timestamp and signature.

Responses

200Slip QR verification result. `data.success` is the business outcome.
401Bad credentials or request signing — missing/malformed Authorization header, unknown key, key not in status `active`, or a missing, invalid, or stale HMAC signature for a key that has signing enabled.
403Key lacks the required scope, or the client IP is not in the merchant allowlist.
404The id is unknown or belongs to another merchant; environment-scoped routes also use 404 without disclosing an object from the other environment.
429Per-key rate limit exceeded — back off and retry.

Payouts

Outbound payments — money you send from your balance.

GET/v1/payouts

List payouts

Newest first. Scope payouts:read. data is a bare array of PayoutView. Prefer cursor + limit for high-volume paging; offset remains for small pages.

Query parameters

limitintegerquery

Page size.

offsetintegerquery

Records to skip for pagination.

cursorstringquery

Stable keyset cursor from the previous page's last row: {RFC3339}_{uuid} built from that row's created_at and id. Mutually exclusive with a non-zero offset. Ordering is (created_at DESC, id DESC).

statusenum (pending | processing | success | failed | cancelled)query
currencystringquery
qstringquery

Headers

X-Signaturestringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send the lowercase hexadecimal HMAC-SHA256 of METHOD\nPATH_AND_QUERY\nTIMESTAMP\nIDEMPOTENCY_KEY\nBODY using the reusable hs_... signing secret revealed once. METHOD is the exact method token sent. PATH_AND_QUERY is the exact raw, already-encoded path and query received by the server; do not decode, normalize, or sort it. IDEMPOTENCY_KEY is the exact header value, or an empty string when absent. BODY is the raw request body bytes, or empty bytes when absent.

X-Signature-Timestampstringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send canonical base-10 Unix seconds within ±300 seconds of server time and sign the same value. For a retry of the same logical operation, reuse the original Idempotency-Key but create a fresh timestamp and signature.

Responses

200A bare array of payouts, wrapped in the ApiResponse envelope.
401Bad credentials or request signing — missing/malformed Authorization header, unknown key, key not in status `active`, or a missing, invalid, or stale HMAC signature for a key that has signing enabled.
403Key lacks the required scope, or the client IP is not in the merchant allowlist.
429Per-key rate limit exceeded — back off and retry.
POST/v1/payouts

Send a payout

Send money from the API key's environment balance to a counterparty account in that same environment. Scope payouts:write. Idempotent: an Idempotency-Key header is required. The gross amount is debited through a hold that is placed and captured atomically before the API returns processing; the captured hold is therefore no longer reported as held. A send is rejected with 422 before any money moves if available balance is insufficient. order_ref is unique per merchant and environment. Test requests use the sandbox simulator and never dispatch a live bank/provider command.

Headers

X-Signaturestringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send the lowercase hexadecimal HMAC-SHA256 of METHOD\nPATH_AND_QUERY\nTIMESTAMP\nIDEMPOTENCY_KEY\nBODY using the reusable hs_... signing secret revealed once. METHOD is the exact method token sent. PATH_AND_QUERY is the exact raw, already-encoded path and query received by the server; do not decode, normalize, or sort it. IDEMPOTENCY_KEY is the exact header value, or an empty string when absent. BODY is the raw request body bytes, or empty bytes when absent.

X-Signature-Timestampstringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send canonical base-10 Unix seconds within ±300 seconds of server time and sign the same value. For a retry of the same logical operation, reuse the original Idempotency-Key but create a fresh timestamp and signature.

Idempotency-Keystringheaderrequired

Opaque unique value for one logical operation. UUID v7 is recommended for new values but not required; reuse the same key for every retry. The namespace is (merchant, environment, key), so the same value may be used independently in test and live. Request identity is SHA256(POST + "\n" + ROUTE_PATH + "\n" + RAW_BODY): ROUTE_PATH is the already-encoded route path visible to the /v1 router after Axum strips the /v1 mount prefix (for example, client path /v1/payins hashes /payins); query excluded; do not decode, normalize, or sort. The raw body is the exact request body bytes (do not parse or reserialize). This layer applies only to POST; other methods bypass it. Same key + same route path and raw body replays the original 2xx response with header idempotent-replay: true. Same key + different route path or raw body → 409.

Body (PayoutCreate)

order_refstringrequired

Your unique reference for this payout. Unique per merchant and environment; a duplicate in the same environment is a 409.

amountinteger (int64)required
dest_account_idstring (uuid)required

UUID of a provisioned counterparty account (the destination bank account). No inline bank details are sent.

client_operation_idstring,null (uuid)

Optional client-side operation UUID for extra dedupe. UUID v7 is recommended for new values; historical UUID versions already stored are still accepted on read.

Responses

200The payout, wrapped in the ApiResponse envelope.
400Malformed request identity or amount — including an unknown/inactive currency for new admission, non-positive or unit-step-misaligned money, an invalid fee split, or malformed customer fields.
401Bad credentials or request signing — missing/malformed Authorization header, unknown key, key not in status `active`, or a missing, invalid, or stale HMAC signature for a key that has signing enabled.
403Key lacks the required scope, or the client IP is not in the merchant allowlist.
409Idempotency-Key reused for a different request identity (route path or raw request body), a request already in progress, or a duplicate order_ref.
422A structurally known request cannot run now — for example the exact live payin collection rail is not enabled, a destination is inactive/unverified for the operation, the same-currency available balance is insufficient (including an empty settlement sweep), or no matching P2P payout liquidity and no collection-rail fallback is available for a direct P2P payin (`P2P_LIQUIDITY_UNAVAILABLE`).
429Per-key rate limit exceeded — back off and retry.
GET/v1/payouts/{id}

Get a payout

Scope payouts:read. Returns the payout, or 404 if the id is unknown or belongs to another merchant.

Path parameters

idstring (uuid)pathrequired

Payout UUID.

Headers

X-Signaturestringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send the lowercase hexadecimal HMAC-SHA256 of METHOD\nPATH_AND_QUERY\nTIMESTAMP\nIDEMPOTENCY_KEY\nBODY using the reusable hs_... signing secret revealed once. METHOD is the exact method token sent. PATH_AND_QUERY is the exact raw, already-encoded path and query received by the server; do not decode, normalize, or sort it. IDEMPOTENCY_KEY is the exact header value, or an empty string when absent. BODY is the raw request body bytes, or empty bytes when absent.

X-Signature-Timestampstringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send canonical base-10 Unix seconds within ±300 seconds of server time and sign the same value. For a retry of the same logical operation, reuse the original Idempotency-Key but create a fresh timestamp and signature.

Responses

200The payout, wrapped in the ApiResponse envelope.
401Bad credentials or request signing — missing/malformed Authorization header, unknown key, key not in status `active`, or a missing, invalid, or stale HMAC signature for a key that has signing enabled.
403Key lacks the required scope, or the client IP is not in the merchant allowlist.
404The id is unknown or belongs to another merchant; environment-scoped routes also use 404 without disclosing an object from the other environment.
429Per-key rate limit exceeded — back off and retry.
POST/v1/payouts/{id}/cancel

Cancel a payout

Scope payouts:write. Idempotent (Idempotency-Key required). Allowed while the payout is pending or processing. Refunds the gross debit, releases the daily limit reservation, and writes audit with actor api_key. Terminal replays return the existing view.

Path parameters

idstring (uuid)pathrequired

Payout UUID.

Headers

X-Signaturestringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send the lowercase hexadecimal HMAC-SHA256 of METHOD\nPATH_AND_QUERY\nTIMESTAMP\nIDEMPOTENCY_KEY\nBODY using the reusable hs_... signing secret revealed once. METHOD is the exact method token sent. PATH_AND_QUERY is the exact raw, already-encoded path and query received by the server; do not decode, normalize, or sort it. IDEMPOTENCY_KEY is the exact header value, or an empty string when absent. BODY is the raw request body bytes, or empty bytes when absent.

X-Signature-Timestampstringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send canonical base-10 Unix seconds within ±300 seconds of server time and sign the same value. For a retry of the same logical operation, reuse the original Idempotency-Key but create a fresh timestamp and signature.

Idempotency-Keystringheaderrequired

Opaque unique value for one logical operation. UUID v7 is recommended for new values but not required; reuse the same key for every retry. The namespace is (merchant, environment, key), so the same value may be used independently in test and live. Request identity is SHA256(POST + "\n" + ROUTE_PATH + "\n" + RAW_BODY): ROUTE_PATH is the already-encoded route path visible to the /v1 router after Axum strips the /v1 mount prefix (for example, client path /v1/payins hashes /payins); query excluded; do not decode, normalize, or sort. The raw body is the exact request body bytes (do not parse or reserialize). This layer applies only to POST; other methods bypass it. Same key + same route path and raw body replays the original 2xx response with header idempotent-replay: true. Same key + different route path or raw body → 409.

Responses

200The payout, wrapped in the ApiResponse envelope.
401Bad credentials or request signing — missing/malformed Authorization header, unknown key, key not in status `active`, or a missing, invalid, or stale HMAC signature for a key that has signing enabled.
403Key lacks the required scope, or the client IP is not in the merchant allowlist.
404The id is unknown or belongs to another merchant; environment-scoped routes also use 404 without disclosing an object from the other environment.
409Idempotency-Key reused for a different request identity (route path or raw request body), a request already in progress, or a duplicate order_ref.
429Per-key rate limit exceeded — back off and retry.
POST/v1/payouts/{id}/test-confirm

Confirm a sandbox payout

Sandbox simulator for integration tests. Scope payouts:write; the calling key and target payout must both be test. Requires Idempotency-Key. Transitions a processing test payout to success, updates the linked payout_attempts row, emits payout.succeeded with livemode: false, and never calls a live bank/provider command. A live key is rejected with 403; an object from the other environment is not disclosed.

Path parameters

idstring (uuid)pathrequired

Payout UUID.

Headers

X-Signaturestringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send the lowercase hexadecimal HMAC-SHA256 of METHOD\nPATH_AND_QUERY\nTIMESTAMP\nIDEMPOTENCY_KEY\nBODY using the reusable hs_... signing secret revealed once. METHOD is the exact method token sent. PATH_AND_QUERY is the exact raw, already-encoded path and query received by the server; do not decode, normalize, or sort it. IDEMPOTENCY_KEY is the exact header value, or an empty string when absent. BODY is the raw request body bytes, or empty bytes when absent.

X-Signature-Timestampstringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send canonical base-10 Unix seconds within ±300 seconds of server time and sign the same value. For a retry of the same logical operation, reuse the original Idempotency-Key but create a fresh timestamp and signature.

Idempotency-Keystringheaderrequired

Opaque unique value for one logical operation. UUID v7 is recommended for new values but not required; reuse the same key for every retry. The namespace is (merchant, environment, key), so the same value may be used independently in test and live. Request identity is SHA256(POST + "\n" + ROUTE_PATH + "\n" + RAW_BODY): ROUTE_PATH is the already-encoded route path visible to the /v1 router after Axum strips the /v1 mount prefix (for example, client path /v1/payins hashes /payins); query excluded; do not decode, normalize, or sort. The raw body is the exact request body bytes (do not parse or reserialize). This layer applies only to POST; other methods bypass it. Same key + same route path and raw body replays the original 2xx response with header idempotent-replay: true. Same key + different route path or raw body → 409.

Responses

200The payout, wrapped in the ApiResponse envelope.
401Bad credentials or request signing — missing/malformed Authorization header, unknown key, key not in status `active`, or a missing, invalid, or stale HMAC signature for a key that has signing enabled.
403Key lacks the required scope, or the client IP is not in the merchant allowlist.
404The id is unknown or belongs to another merchant; environment-scoped routes also use 404 without disclosing an object from the other environment.
409Idempotency-Key reused for a different request identity (route path or raw request body), a request already in progress, or a duplicate order_ref.
429Per-key rate limit exceeded — back off and retry.

Settlements

Sweeps from your balance to a verified destination.

GET/v1/settlements

List settlements

Newest first in the API key's environment. Scope settlements:read. data is a bare array of SettlementView. Prefer cursor + limit for high-volume paging; offset remains for small pages.

Query parameters

limitintegerquery

Page size.

offsetintegerquery

Records to skip for pagination.

cursorstringquery

Stable keyset cursor from the previous page's last row: {RFC3339}_{uuid} built from that row's created_at and id. Mutually exclusive with a non-zero offset. Ordering is (created_at DESC, id DESC).

statusenum (pending | processing | completed | failed)query
currencystringquery

Headers

X-Signaturestringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send the lowercase hexadecimal HMAC-SHA256 of METHOD\nPATH_AND_QUERY\nTIMESTAMP\nIDEMPOTENCY_KEY\nBODY using the reusable hs_... signing secret revealed once. METHOD is the exact method token sent. PATH_AND_QUERY is the exact raw, already-encoded path and query received by the server; do not decode, normalize, or sort it. IDEMPOTENCY_KEY is the exact header value, or an empty string when absent. BODY is the raw request body bytes, or empty bytes when absent.

X-Signature-Timestampstringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send canonical base-10 Unix seconds within ±300 seconds of server time and sign the same value. For a retry of the same logical operation, reuse the original Idempotency-Key but create a fresh timestamp and signature.

Responses

200A bare array of settlements, wrapped in the ApiResponse envelope.
401Bad credentials or request signing — missing/malformed Authorization header, unknown key, key not in status `active`, or a missing, invalid, or stale HMAC signature for a key that has signing enabled.
403Key lacks the required scope, or the client IP is not in the merchant allowlist.
429Per-key rate limit exceeded — back off and retry.
POST/v1/settlements

Create a settlement

Sweep all or part of the API key's environment balance to a verified counterparty account in that same environment. Scope settlements:write. Idempotent: an Idempotency-Key header is required. Test requests use the sandbox simulator and never dispatch a live bank/provider command.

Headers

X-Signaturestringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send the lowercase hexadecimal HMAC-SHA256 of METHOD\nPATH_AND_QUERY\nTIMESTAMP\nIDEMPOTENCY_KEY\nBODY using the reusable hs_... signing secret revealed once. METHOD is the exact method token sent. PATH_AND_QUERY is the exact raw, already-encoded path and query received by the server; do not decode, normalize, or sort it. IDEMPOTENCY_KEY is the exact header value, or an empty string when absent. BODY is the raw request body bytes, or empty bytes when absent.

X-Signature-Timestampstringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send canonical base-10 Unix seconds within ±300 seconds of server time and sign the same value. For a retry of the same logical operation, reuse the original Idempotency-Key but create a fresh timestamp and signature.

Idempotency-Keystringheaderrequired

Opaque unique value for one logical operation. UUID v7 is recommended for new values but not required; reuse the same key for every retry. The namespace is (merchant, environment, key), so the same value may be used independently in test and live. Request identity is SHA256(POST + "\n" + ROUTE_PATH + "\n" + RAW_BODY): ROUTE_PATH is the already-encoded route path visible to the /v1 router after Axum strips the /v1 mount prefix (for example, client path /v1/payins hashes /payins); query excluded; do not decode, normalize, or sort. The raw body is the exact request body bytes (do not parse or reserialize). This layer applies only to POST; other methods bypass it. Same key + same route path and raw body replays the original 2xx response with header idempotent-replay: true. Same key + different route path or raw body → 409.

Body (SettlementCreate)

dest_account_idstring (uuid)required

UUID of a verified counterparty account in the API key's environment.

amountobject

Optional gross amount in the destination account currency's minor units. Omit or send null to sweep the full currently available balance for that currency in the key's environment.

client_operation_idstring,null (uuid)

Optional client-side operation UUID for extra dedupe. UUID v7 is recommended for new values; historical UUID versions already stored are still accepted on read.

Responses

200The settlement, wrapped in the ApiResponse envelope.
400Malformed request identity or amount — including an unknown/inactive currency for new admission, non-positive or unit-step-misaligned money, an invalid fee split, or malformed customer fields.
401Bad credentials or request signing — missing/malformed Authorization header, unknown key, key not in status `active`, or a missing, invalid, or stale HMAC signature for a key that has signing enabled.
403Key lacks the required scope, or the client IP is not in the merchant allowlist.
409Idempotency-Key reused for a different request identity (route path or raw request body), a request already in progress, or a duplicate order_ref.
422A structurally known request cannot run now — for example the exact live payin collection rail is not enabled, a destination is inactive/unverified for the operation, the same-currency available balance is insufficient (including an empty settlement sweep), or no matching P2P payout liquidity and no collection-rail fallback is available for a direct P2P payin (`P2P_LIQUIDITY_UNAVAILABLE`).
429Per-key rate limit exceeded — back off and retry.
GET/v1/settlements/{id}

Get a settlement

Scope settlements:read. Returns the settlement from the API key's environment, or 404 without disclosing an object from another merchant or environment.

Path parameters

idstring (uuid)pathrequired

Settlement UUID.

Headers

X-Signaturestringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send the lowercase hexadecimal HMAC-SHA256 of METHOD\nPATH_AND_QUERY\nTIMESTAMP\nIDEMPOTENCY_KEY\nBODY using the reusable hs_... signing secret revealed once. METHOD is the exact method token sent. PATH_AND_QUERY is the exact raw, already-encoded path and query received by the server; do not decode, normalize, or sort it. IDEMPOTENCY_KEY is the exact header value, or an empty string when absent. BODY is the raw request body bytes, or empty bytes when absent.

X-Signature-Timestampstringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send canonical base-10 Unix seconds within ±300 seconds of server time and sign the same value. For a retry of the same logical operation, reuse the original Idempotency-Key but create a fresh timestamp and signature.

Responses

200The settlement, wrapped in the ApiResponse envelope.
401Bad credentials or request signing — missing/malformed Authorization header, unknown key, key not in status `active`, or a missing, invalid, or stale HMAC signature for a key that has signing enabled.
403Key lacks the required scope, or the client IP is not in the merchant allowlist.
404The id is unknown or belongs to another merchant; environment-scoped routes also use 404 without disclosing an object from the other environment.
429Per-key rate limit exceeded — back off and retry.

Balance

Spendable balance, per currency.

GET/v1/balance

Get balance

Your spendable balance in the API key's environment, broken out per currency. Scope balance:read. available already excludes outstanding uncaptured holds; a current processing payout has captured its hold and is reflected by its gross balance debit instead. data is a bare array; every item carries livemode.

Headers

X-Signaturestringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send the lowercase hexadecimal HMAC-SHA256 of METHOD\nPATH_AND_QUERY\nTIMESTAMP\nIDEMPOTENCY_KEY\nBODY using the reusable hs_... signing secret revealed once. METHOD is the exact method token sent. PATH_AND_QUERY is the exact raw, already-encoded path and query received by the server; do not decode, normalize, or sort it. IDEMPOTENCY_KEY is the exact header value, or an empty string when absent. BODY is the raw request body bytes, or empty bytes when absent.

X-Signature-Timestampstringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send canonical base-10 Unix seconds within ±300 seconds of server time and sign the same value. For a retry of the same logical operation, reuse the original Idempotency-Key but create a fresh timestamp and signature.

Responses

200Per-currency balances, wrapped in the ApiResponse envelope.
401Bad credentials or request signing — missing/malformed Authorization header, unknown key, key not in status `active`, or a missing, invalid, or stale HMAC signature for a key that has signing enabled.
403Key lacks the required scope, or the client IP is not in the merchant allowlist.
429Per-key rate limit exceeded — back off and retry.

Sandbox

Test-only balance funding and integration tools.

POST/v1/sandbox/top-up

Top up a sandbox balance

Test-only wallet funding for integration tests. Requires an active sk_test_ key with scope sandbox:topup and an Idempotency-Key (1–128 visible ASCII characters for this operation). Test keys issued before this scope was added must be regenerated to use it. The server fixes the merchant and test environment from the key; a live key is rejected with 403, and request fields cannot select a live wallet. amount_minor is a positive integer in the currency's minor units, at most 10000000 per request and divisible by its server-owned unit_step; the currency must be active. A balanced PostgreSQL journal and test-wallet credit commit atomically; the receipt carries livemode: false. Repeating the same key and raw request replays the receipt without another credit.

Headers

X-Signaturestringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send the lowercase hexadecimal HMAC-SHA256 of METHOD\nPATH_AND_QUERY\nTIMESTAMP\nIDEMPOTENCY_KEY\nBODY using the reusable hs_... signing secret revealed once. METHOD is the exact method token sent. PATH_AND_QUERY is the exact raw, already-encoded path and query received by the server; do not decode, normalize, or sort it. IDEMPOTENCY_KEY is the exact header value, or an empty string when absent. BODY is the raw request body bytes, or empty bytes when absent.

X-Signature-Timestampstringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send canonical base-10 Unix seconds within ±300 seconds of server time and sign the same value. For a retry of the same logical operation, reuse the original Idempotency-Key but create a fresh timestamp and signature.

Idempotency-Keystringheaderrequired

Opaque unique value for one logical operation. UUID v7 is recommended for new values but not required; reuse the same key for every retry. The namespace is (merchant, environment, key), so the same value may be used independently in test and live. Request identity is SHA256(POST + "\n" + ROUTE_PATH + "\n" + RAW_BODY): ROUTE_PATH is the already-encoded route path visible to the /v1 router after Axum strips the /v1 mount prefix (for example, client path /v1/payins hashes /payins); query excluded; do not decode, normalize, or sort. The raw body is the exact request body bytes (do not parse or reserialize). This layer applies only to POST; other methods bypass it. Same key + same route path and raw body replays the original 2xx response with header idempotent-replay: true. Same key + different route path or raw body → 409.

Body (SandboxTopUpRequest)

currencystringrequired
amount_minorinteger (int64)required

Positive integer amount in the currency's minor units; must be divisible by its server-owned unit_step.

Responses

200Test-wallet credit receipt wrapped in the ApiResponse envelope.
400Malformed request identity or amount — including an unknown/inactive currency for new admission, non-positive or unit-step-misaligned money, an invalid fee split, or malformed customer fields.
401Bad credentials or request signing — missing/malformed Authorization header, unknown key, key not in status `active`, or a missing, invalid, or stale HMAC signature for a key that has signing enabled.
403Key lacks the required scope, or the client IP is not in the merchant allowlist.
409Idempotency-Key reused for a different request identity (route path or raw request body), a request already in progress, or a duplicate order_ref.
422A structurally known request cannot run now — for example the exact live payin collection rail is not enabled, a destination is inactive/unverified for the operation, the same-currency available balance is insufficient (including an empty settlement sweep), or no matching P2P payout liquidity and no collection-rail fallback is available for a direct P2P payin (`P2P_LIQUIDITY_UNAVAILABLE`).
429Per-key rate limit exceeded — back off and retry.
503A test-write emergency fence or money-authority containment gate prevents funding.

Customers

Counterparty bank accounts — payout and settlement destinations.

GET/v1/bank/verify

Verify bank account holder name

Live-only lookup of the registered holder name for a Thai bank account. Scope bank:verify. Only sk_live_ keys may reach the shared production cache or configured upstream provider; sk_test_ is rejected with 403 before either path. A cache hit does not call the upstream provider. This endpoint does not set is_verified on a customer record.

Query parameters

bank_codestringqueryrequired

Thai bank code (uppercased on lookup).

account_nostringqueryrequired

Destination account number (6–20 digits).

Headers

X-Signaturestringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send the lowercase hexadecimal HMAC-SHA256 of METHOD\nPATH_AND_QUERY\nTIMESTAMP\nIDEMPOTENCY_KEY\nBODY using the reusable hs_... signing secret revealed once. METHOD is the exact method token sent. PATH_AND_QUERY is the exact raw, already-encoded path and query received by the server; do not decode, normalize, or sort it. IDEMPOTENCY_KEY is the exact header value, or an empty string when absent. BODY is the raw request body bytes, or empty bytes when absent.

X-Signature-Timestampstringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send canonical base-10 Unix seconds within ±300 seconds of server time and sign the same value. For a retry of the same logical operation, reuse the original Idempotency-Key but create a fresh timestamp and signature.

Responses

200Bank account holder name lookup result.
401Bad credentials or request signing — missing/malformed Authorization header, unknown key, key not in status `active`, or a missing, invalid, or stale HMAC signature for a key that has signing enabled.
403Key lacks the required scope, or the client IP is not in the merchant allowlist.
404The id is unknown or belongs to another merchant; environment-scoped routes also use 404 without disclosing an object from the other environment.
429Per-key rate limit exceeded — back off and retry.
503Bank name verification is disabled on this deployment.
GET/v1/customers

List customers

Newest first in the API key's environment. Scope customers:read. data is a bare array of CustomerView.

Query parameters

limitintegerquery

Page size.

offsetintegerquery

Records to skip for pagination.

cursorstringquery

Stable keyset cursor from the previous page's last row: {RFC3339}_{uuid} built from that row's created_at and id. Mutually exclusive with a non-zero offset. Ordering is (created_at DESC, id DESC).

statusenum (active | blocked | archived)query
bank_codestringquery
qstringquery

Headers

X-Signaturestringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send the lowercase hexadecimal HMAC-SHA256 of METHOD\nPATH_AND_QUERY\nTIMESTAMP\nIDEMPOTENCY_KEY\nBODY using the reusable hs_... signing secret revealed once. METHOD is the exact method token sent. PATH_AND_QUERY is the exact raw, already-encoded path and query received by the server; do not decode, normalize, or sort it. IDEMPOTENCY_KEY is the exact header value, or an empty string when absent. BODY is the raw request body bytes, or empty bytes when absent.

X-Signature-Timestampstringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send canonical base-10 Unix seconds within ±300 seconds of server time and sign the same value. For a retry of the same logical operation, reuse the original Idempotency-Key but create a fresh timestamp and signature.

Responses

200A bare array of customers, wrapped in the ApiResponse envelope.
401Bad credentials or request signing — missing/malformed Authorization header, unknown key, key not in status `active`, or a missing, invalid, or stale HMAC signature for a key that has signing enabled.
403Key lacks the required scope, or the client IP is not in the merchant allowlist.
429Per-key rate limit exceeded — back off and retry.
POST/v1/customers

Create a customer

Register a counterparty bank account in the API key's environment. Scope customers:write. Idempotent: an Idempotency-Key header is required. The pair (bank_code, account_no) must be unique per merchant and environment; test and live records are isolated. Sandbox customers are auto-verified for simulator-only settlement use without calling the live bank verifier; new live customers remain unverified until the dashboard finance flow verifies them.

Headers

X-Signaturestringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send the lowercase hexadecimal HMAC-SHA256 of METHOD\nPATH_AND_QUERY\nTIMESTAMP\nIDEMPOTENCY_KEY\nBODY using the reusable hs_... signing secret revealed once. METHOD is the exact method token sent. PATH_AND_QUERY is the exact raw, already-encoded path and query received by the server; do not decode, normalize, or sort it. IDEMPOTENCY_KEY is the exact header value, or an empty string when absent. BODY is the raw request body bytes, or empty bytes when absent.

X-Signature-Timestampstringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send canonical base-10 Unix seconds within ±300 seconds of server time and sign the same value. For a retry of the same logical operation, reuse the original Idempotency-Key but create a fresh timestamp and signature.

Idempotency-Keystringheaderrequired

Opaque unique value for one logical operation. UUID v7 is recommended for new values but not required; reuse the same key for every retry. The namespace is (merchant, environment, key), so the same value may be used independently in test and live. Request identity is SHA256(POST + "\n" + ROUTE_PATH + "\n" + RAW_BODY): ROUTE_PATH is the already-encoded route path visible to the /v1 router after Axum strips the /v1 mount prefix (for example, client path /v1/payins hashes /payins); query excluded; do not decode, normalize, or sort. The raw body is the exact request body bytes (do not parse or reserialize). This layer applies only to POST; other methods bypass it. Same key + same route path and raw body replays the original 2xx response with header idempotent-replay: true. Same key + different route path or raw body → 409.

Body (CustomerCreate)

holder_namestringrequired

Bank account holder name.

bank_codestringrequired

Bank or rail-institution code, uppercased on store (e.g. KBANK). The Bank codes page lists the supported Thai-bank catalog used by the current THB tooling and holder-name verification rail.

account_nostringrequired

Destination account number (6–20 digits).

currencystring

Defaults to THB.

Responses

200The customer, wrapped in the ApiResponse envelope.
400Malformed request identity or amount — including an unknown/inactive currency for new admission, non-positive or unit-step-misaligned money, an invalid fee split, or malformed customer fields.
401Bad credentials or request signing — missing/malformed Authorization header, unknown key, key not in status `active`, or a missing, invalid, or stale HMAC signature for a key that has signing enabled.
403Key lacks the required scope, or the client IP is not in the merchant allowlist.
409Idempotency-Key reused for a different request identity (route path or raw request body), a request already in progress, or a duplicate order_ref.
422A structurally known request cannot run now — for example the exact live payin collection rail is not enabled, a destination is inactive/unverified for the operation, the same-currency available balance is insufficient (including an empty settlement sweep), or no matching P2P payout liquidity and no collection-rail fallback is available for a direct P2P payin (`P2P_LIQUIDITY_UNAVAILABLE`).
429Per-key rate limit exceeded — back off and retry.
GET/v1/customers/{id}

Get a customer

Scope customers:read. Returns the customer from the API key's environment, or 404 without disclosing an object from another merchant or environment.

Path parameters

idstring (uuid)pathrequired

Customer (counterparty account) UUID.

Headers

X-Signaturestringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send the lowercase hexadecimal HMAC-SHA256 of METHOD\nPATH_AND_QUERY\nTIMESTAMP\nIDEMPOTENCY_KEY\nBODY using the reusable hs_... signing secret revealed once. METHOD is the exact method token sent. PATH_AND_QUERY is the exact raw, already-encoded path and query received by the server; do not decode, normalize, or sort it. IDEMPOTENCY_KEY is the exact header value, or an empty string when absent. BODY is the raw request body bytes, or empty bytes when absent.

X-Signature-Timestampstringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send canonical base-10 Unix seconds within ±300 seconds of server time and sign the same value. For a retry of the same logical operation, reuse the original Idempotency-Key but create a fresh timestamp and signature.

Responses

200The customer, wrapped in the ApiResponse envelope.
401Bad credentials or request signing — missing/malformed Authorization header, unknown key, key not in status `active`, or a missing, invalid, or stale HMAC signature for a key that has signing enabled.
403Key lacks the required scope, or the client IP is not in the merchant allowlist.
404The id is unknown or belongs to another merchant; environment-scoped routes also use 404 without disclosing an object from the other environment.
429Per-key rate limit exceeded — back off and retry.
PATCH/v1/customers/{id}

Update a customer

Scope customers:write. Updates only a customer in the API key's environment; an id from the other environment is not disclosed. Body carries only the fields you want to change. trust_score and is_verified are read-only over /v1 — they move only through the live dashboard finance flow.

Path parameters

idstring (uuid)pathrequired

Customer (counterparty account) UUID.

Headers

X-Signaturestringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send the lowercase hexadecimal HMAC-SHA256 of METHOD\nPATH_AND_QUERY\nTIMESTAMP\nIDEMPOTENCY_KEY\nBODY using the reusable hs_... signing secret revealed once. METHOD is the exact method token sent. PATH_AND_QUERY is the exact raw, already-encoded path and query received by the server; do not decode, normalize, or sort it. IDEMPOTENCY_KEY is the exact header value, or an empty string when absent. BODY is the raw request body bytes, or empty bytes when absent.

X-Signature-Timestampstringheader

Optional unless HMAC request signing is enabled for the authenticated API key in either environment. When enabled, send canonical base-10 Unix seconds within ±300 seconds of server time and sign the same value. For a retry of the same logical operation, reuse the original Idempotency-Key but create a fresh timestamp and signature.

Body (CustomerUpdate)

holder_namestring

New bank account holder name.

statusenum (active | blocked | archived)

Set blocked to stop new payouts/settlements; archived to retire the account.

Responses

200The customer, wrapped in the ApiResponse envelope.
400Malformed request identity or amount — including an unknown/inactive currency for new admission, non-positive or unit-step-misaligned money, an invalid fee split, or malformed customer fields.
401Bad credentials or request signing — missing/malformed Authorization header, unknown key, key not in status `active`, or a missing, invalid, or stale HMAC signature for a key that has signing enabled.
403Key lacks the required scope, or the client IP is not in the merchant allowlist.
404The id is unknown or belongs to another merchant; environment-scoped routes also use 404 without disclosing an object from the other environment.
422A structurally known request cannot run now — for example the exact live payin collection rail is not enabled, a destination is inactive/unverified for the operation, the same-currency available balance is insufficient (including an empty settlement sweep), or no matching P2P payout liquidity and no collection-rail fallback is available for a direct P2P payin (`P2P_LIQUIDITY_UNAVAILABLE`).
429Per-key rate limit exceeded — back off and retry.

Models

ApiErrorobject

Properties

successbooleanrequired
datanullrequired
errorstringrequired

Human-readable message to log.

codestringrequired

Stable machine-readable error code. Branch on this, not on the message text.

Balanceobject

Properties

currencystringrequired
postedinteger (int64)required

Posted merchant liability in the row currency's minor units. Under TigerBeetle authority this is credits_posted minus debits_posted on the merchant-payable account; under PostgreSQL shadow it matches the stored wallet balance before holds.

pendinginteger (int64)required

Pending debits in the row currency's minor units (TigerBeetle debits_pending or, in PostgreSQL shadow, the same total as held).

pending_creditsinteger (int64)required

Pending credits on the merchant-payable account. Never spendable; always excluded from available. Zero in PostgreSQL shadow mode.

availableinteger (int64)required

Spendable now, in the row currency's minor units. Under TigerBeetle authority this is posted minus pending debits; under PostgreSQL shadow it is the stored balance minus outstanding uncaptured holds in the same environment and currency.

heldinteger (int64)required

Compatibility alias for pending debits / outstanding uncaptured reservations in the row currency's minor units. A current processing payout captures its hold atomically and is represented by its gross balance debit, not by this field.

livemodebooleanrequired

True only for a balance in the live financial namespace.

authority_epochinteger (int64)required

Current balance-authority epoch for this environment. Clients must not infer spend authority from stale projections when this epoch advances.

BankVerifyViewobject

Properties

bank_codestringrequired
account_nostringrequired
holder_namestringrequired
cachedbooleanrequired

True when the name was served from the global cache without calling the upstream provider.

verified_atstring (date-time)

When this cache entry was last refreshed.

CryptoDepositobject

Properties

topup_request_idstring (uuid)required

The created USDT deposit request id.

deposit_address_idstring (uuid)required

Id of the freshly minted deposit address.

networkenum (TRC20 | SOLANA | BEP20 | ERC20)required

Crypto network the deposit address is on.

addressstringrequired

On-chain USDT deposit address; send reserved_atomic µUSDT to it.

reserved_atomicinteger (int64)required

Amount to send, in µUSDT.

expires_atstring (date-time)required

When the deposit window closes.

pay_tokenstringrequired

Opaque hosted-pay handle for the crypto deposit page.

Currencystring
CustomerCreateobject

Properties

holder_namestringrequired

Bank account holder name.

bank_codestringrequired

Bank or rail-institution code, uppercased on store (e.g. KBANK). The Bank codes page lists the supported Thai-bank catalog used by the current THB tooling and holder-name verification rail.

account_nostringrequired

Destination account number (6–20 digits).

currencystring

Defaults to THB.