Errors & Idempotency
How the API signals errors, the access-control codes to expect, and how to use idempotency keys safely.
Error responses
The API uses standard HTTP status codes. A 2xx status means success; 4xx means the request was rejected; 5xx means a server or provider error. Errors return a JSON body with a human-readable error, a machine-readable code you can branch on, and a requestId to quote when you contact support:
{
"error": "PIX payouts to this recipient's bank are not supported. ...",
"code": "pix_recipient_bank_not_supported",
"requestId": "4adda759-86ec-4ec5-a3da-e1edc4cc6584"
}
The API returns 503 for temporary server and provider failures. A 502 or 504 response
without that JSON body comes from our edge network, not from the API: the request may or may not
have been processed, so treat it like a timeout and retry with the same Idempotency-Key.
Access-control errors
Product access is checked on every request. When a product is not enabled for your organization, you get a 403 with a specific code:
| Status | Code | Meaning |
|---|---|---|
403 |
banking_api_access_not_enabled |
Banking is not enabled for your organization’s API access. |
403 |
wallet_transfers_not_enabled |
Stablecoin wallet transfers are not enabled for your organization. |
403 |
cards_api_access_not_enabled |
Cards is not enabled for your organization’s API access. |
403 |
api_access_disabled |
Checkout API access is not enabled for your organization. |
If you see one of these, ask your Dolafy contact to enable the product and the org-level API flag.
Common resource errors
| Status | Code | Meaning |
|---|---|---|
400 |
recipient_rail_unsupported |
Recipient creation supports BRL PIX, USD ACH, and USD Wire only. |
400 |
invalid_destination_address |
The Base address is malformed, or a mixed-case address has an invalid EIP-55 checksum. |
404 |
banking_transfer_not_found |
No API-created transfer with that id exists for your organization. |
404 |
recipient_not_found |
No active recipient with that id exists for your organization. |
409 |
recipient_nickname_already_exists |
Another active external recipient already uses this nickname. Choose a different nickname. |
409 |
recipient_partner_sync_failed |
The configured banking route rejected the recipient details; correct them and retry. |
422 |
pix_recipient_bank_not_supported |
PIX payouts to the recipient’s bank are not supported (credit cooperatives such as Sicoob). No funds were sent. Use a PIX key registered at a different bank. |
422 |
pix_payout_rejected |
The PIX payout was rejected before any funds moved; the message says why. Correct the recipient and retry. |
422 |
pix_quote_rejected |
The PIX quote was rejected (for example an amount outside the allowed range); the message says why. |
409 |
wallet_recipient_required |
Save and activate this Base USDC wallet recipient in the dashboard before sending through the API. |
409 |
authorized_user_terms_required |
Card authorized-user terms must be accepted in the dashboard before issuing cards via the API. |
400 |
invalid_checkout_session_amount |
A checkout-session amount is not a positive supported decimal with at most two decimal places. |
400 |
checkout_session_pricing_conflict |
A checkout session supplied both amount and discountPercent; provide only one. |
503 |
checkout_pix_not_available |
The organization is not set up to accept PIX for checkout yet. |
503 |
provider_rate_limited |
The card provider is briefly rate limited. Nothing was processed. Wait the number of seconds in the Retry-After header, then repeat the same request — for POST /v1/cards, with the same Idempotency-Key. |
Idempotency
Some write endpoints require an Idempotency-Key header so that retries never create duplicates:
POST /v1/banking/recipientsPOST /v1/banking/transfersPOST /v1/cardsPOST /v1/checkout/productsPOST /v1/checkout/sessions
For the checkout endpoints, the key must be 8–200 characters of letters, numbers, dots, underscores, colons, or hyphens.
Your server generates the key. Use a unique value for each new request. Reuse the exact same value only when retrying the same request after a timeout or network error — Dolafy will return the original result instead of performing the action twice.
Banking transfers add two idempotency outcomes you should handle:
| Status | Code | Meaning |
|---|---|---|
409 |
banking_transfer_attempt_pending_review |
An earlier request with this key started a payout whose outcome is still being confirmed. Do not send the same payment under a new key; contact support if it does not resolve. |
409 |
banking_transfer_idempotency_conflict |
This key was already used with a different amount or recipient. Use a new key for a new payment. |
Retrying a transfer funding error
If transfer creation returns a temporary 503 error without a transfer object, wait at
least 60 seconds and retry the same request with the same Idempotency-Key. Use increasing delays
with jitter if the error continues. The retry safely resolves the original attempt and may use new
pricing when the previous quote is no longer valid.
Choose the next action from the retry response:
| Retry result | What to do |
|---|---|
201 with pending or completed |
Keep the original key and track that transfer. Do not submit the payment again. |
201 with failed or cancelled |
The original attempt is closed. To try the payment again, create a new request with a new idempotency key. |
409 banking_transfer_attempt_pending_review |
Do not use a new key for the same payment. Contact support if it does not resolve. |
Another temporary 503 |
Keep the same key, increase the delay, and retry later. |
Never switch to a new key only because the first request returned 503 (or an edge 502/504); doing so before the
original outcome is known could create a duplicate payment.
POST /v1/banking/transfers
x-api-key: dlfy_live_...
Idempotency-Key: pix-acme-1048
content-type: application/json
Guidelines:
- Derive the key from your own stable identifier for the operation (for example an invoice or order id).
- Do not reuse a key for a genuinely different request; that returns the original response, not a new one.
- Keys are stored on the created resource and reused for duplicate responses.
- For checkout sessions, the normalized
amount,discountPercent, and selected payment method are part of the request identity. Changing any of them requires a new key; equivalent decimal forms such as37.45and"37.45"are treated as the same amount.