Reference

Errors & limits.

Errors share one envelope. Branch on the HTTP status and the stable code, never on the human-readable message.

The error envelope

response 404
{
  "error": {
    "type": "not_found_error",
    "code": "transaction_not_found",
    "message": "Transaction not found.",
    "param": null,
    "request_id": "…"
  }
}
FieldMeaning
typeA broad category, like authentication_error, invalid_request_error, not_found_error or api_error.
codeA stable machine-readable identifier. Safe to switch on.
messageA human-readable explanation. Wording can change.
paramFor validation errors, the field that caused it.
request_idAlso sent as the X-Request-Id response header. Include it when contacting support.

A malformed body returns 400 validation_failed, with param naming the first offending field. Unexpected server failures return 500 internal_error and are captured for investigation.

Common codes

StatuscodeMeaning
400validation_failedThe request body or query failed validation.
401missing_api_keyNo API key, or the header isn't Bearer sk_…
401invalid_api_keyThe key doesn't exist or was revoked.
404transaction_not_foundThe payment doesn't exist or belongs to another merchant.
404payment_link_not_foundThe checkout link doesn't exist.
400payment_link_expiredThe link's expiry has passed.
400merchant_wallet_not_connectedThe merchant hasn't connected a payout wallet.
400unsupported_wallet_currencypayCurrency isn't one of the supported assets for this network.
400custom_amount_requiredThe link takes a customer-chosen amount but none was sent.
400custom_amount_not_allowedThe link has a fixed amount; don't send one.
400duplicate_transaction_hashThat transaction hash was already used for another payment.
400transaction_not_refundableThe payment isn't in a refundable state.
400refund_amount_exceeds_remainingMore than the remaining refundable balance.
400canary_merchant_not_allowedMerchant isn't on the live mainnet allowlist yet.
400canary_payment_cap_exceededThe payment is above the beta per-payment cap.
503wallet_payments_not_configuredThe server has no blockchain client configured.
503price_unavailableNo exchange rate could be obtained to quote the payment. Safe to retry in a moment.

Rate limits

SurfaceLimit
API-key endpoints (payments, refunds, events, disputes)100 requests per minute
Public checkout endpoints30 requests per minute
Dashboard sign-in5 attempts per minute

Going over a limit returns 429. Note that this response uses a flatter body than the standard envelope:

response 429
{
  "message": "Too many requests. Please slow down and try again shortly.",
  "code": "rate_limited"
}
  • Back off and retry after a short delay rather than retrying immediately.
  • Prefer webhooks over polling to stay well under the limit.

Idempotency

Operations that move money require an Idempotency-Key header. Creating a refund is the one you'll use from your server. Retrying with the same key returns the original result instead of repeating the action. Use a fresh random key (a UUID) per intended action, and reuse it only when retrying that same action.