Troubleshooting Your API Requests
REST error response
Every error response of the Payments API has the same format and contains exactly one error:
{
"code": 7004,
"error_message": "TRANSFER_INSUFFICIENT_FUNDS",
"description": "Insufficient funds on the source account. Check the balance, then fund the source account or reduce the amount."
}
| Field | Type | Use |
|---|---|---|
code | integer | Stable numeric business code. Use it in your error handling. |
error_message | string | Stable public name of the error. Use it in your error handling and logs. |
description | string | Short human-readable hint. The text may change without notice; do not parse it. |
The HTTP status describes the transport and API layer. code and error_message identify the exact problem.
HTTP status guide
| HTTP | Meaning | Codes |
|---|---|---|
| 400 | The request structure is invalid | 3000 |
| 401 | Authentication failed | 1000, 1001 |
| 403 | The operation is not permitted | 1002, 7002 |
| 404 | The account or transfer was not found | 2000, 7010 |
| 409 | Conflict with the idempotency key or the account state | 3016, 7004 |
| 422 | Request parameters or transfer rules validation failed | 3001, 7000, 7001, 7003, 7005, 7006, 7007, 7009 |
| 429 | Rate limit exceeded | 3015 |
| 500 | Internal error, or the transfer outcome is unknown | 3, 7008 |
| 503 | Service temporarily unavailable | 2 |
Payments API error codes
The Retry column describes automatic retries. No means that repeating the request without fixing the cause will not help; it does not prevent you from sending a corrected request. After fixing authentication or permissions, resend the same transfer request with the same idempotency key. After a rate-limit error, wait and reduce the request rate before resending.
For transfer creation, the client actions apply while no request sent with the idempotency key has had an unknown outcome. After an unknown outcome, an error on a retry leaves the outcome unknown: do not change the request or the key to get past the error. Follow Recovery and idempotency to decide whether to resend, fix the cause, or close the record and check Transaction History.
Operations: Create — POST /v1/transfers; Balance — GET /v1/accounts/{account_id}/balance; Status — GET /v1/transfers/{transfer_id}.
| HTTP | code | error_message | Returned by | Retry | Client action |
|---|---|---|---|---|---|
| 400 | 3000 | REQUEST_INVALID | All | No | The body is not valid JSON. Fix the request structure. |
| 401 | 1000 | AUTH_INVALID_API_KEY | All | No | The API key is invalid or inactive. Check the key. |
| 401 | 1001 | AUTH_INVALID_SIGNATURE | All | No | Signature verification failed. Check the signing steps; see the checklist below. |
| 403 | 1002 | AUTH_PERMISSION_DENIED | All | No | The operation is outside the scopes of the key, or your source IP is not allowed for the key. Check the scopes and the allowed IPs of the key. |
| 403 | 7002 | TRANSFER_SOURCE_NOT_ALLOWED | Create | No | The source account is not your Partner Reward Wallet. Use your Reward Wallet for transfers to another client. |
| 404 | 2000 | ACCOUNT_NOT_FOUND | Create, Balance | No | The account does not exist, is not available to your key, or does not match destination_type. Check the account number. |
| 404 | 7010 | TRANSFER_NOT_FOUND | Status | No | The transfer does not exist, you are neither its sender nor its recipient, or its type is not covered by the scopes of your key. Check the identifier. |
| 409 | 3016 | REQUEST_IDEMPOTENCY_KEY_REUSED | Create | No | The key was already used with a different request. On a retry, resend the original request unchanged with the same key. For a new transfer, generate a new key. |
| 409 | 7004 | TRANSFER_INSUFFICIENT_FUNDS | Create | No | Not enough funds on the source account. Fund the account or reduce the amount. |
| 422 | 3001 | REQUEST_INVALID_PARAMETERS | All | No | Parameters did not pass validation: a required field is missing, or a value has a wrong type or format. Check the request against the field rules. |
| 422 | 7000 | TRANSFER_NOT_SUPPORTED | Create | No | The account combination is not supported. Choose different accounts. |
| 422 | 7001 | TRANSFER_DESTINATION_NOT_SUPPORTED | Create | No | Transfers to this destination are not supported. Choose another destination account. |
| 422 | 7003 | OPERATION_NOT_ALLOWED | Create | No | The operation is not allowed for your account. Check account eligibility or contact support. |
| 422 | 7005 | TRANSFER_AMOUNT_TOO_SMALL | Create | No | Increase the amount. |
| 422 | 7006 | TRANSFER_AMOUNT_TOO_LARGE | Create | No | Reduce the amount. |
| 422 | 7007 | TRANSFER_LIMIT_REACHED | Create | Later | Try again later. Changing the amount does not help. |
| 422 | 7009 | TRANSFER_MT_ACCOUNT_NOT_SUPPORTED | Create | No | MT4 and MT5 accounts are not supported. Choose an account on the Exness platform. |
| 429 | 3015 | REQUEST_RATE_LIMIT | All | After a wait | Wait before sending another request and reduce the request rate; see API Configuration and Limits. |
| 500 | 3 | SYSTEM_INTERNAL_ERROR | All | Yes, with exponential backoff | For transfer creation, reuse the same idempotency key and the same request: the outcome is unknown. Contact support if it repeats. |
| 500 | 7008 | TRANSFER_OUTCOME_UNKNOWN | Create | Same key only | Resend the exact same request with the same idempotency key. See Recovery and idempotency. |
| 503 | 2 | SYSTEM_TEMPORARY_UNAVAILABLE | All | Yes, with exponential backoff | For transfer creation, reuse the same idempotency key and the same request: the outcome is unknown. |
Best practices for handling errors
Branch on the code
Use
codeorerror_message, neverdescriptionor the HTTP status alone.Check before retrying
Use automatic retries only where the table allows them. Otherwise, fix the cause first and follow the recovery rules for transfer creation.
Reuse the key on retries
For every retry of a creation request, reuse the same idempotency key and the exact same request.
New key only for a new transfer
Use a new idempotency key only for a new transfer, after the outcome of the previous attempt is confirmed. If you stop sending a transfer without a
201, retire its key first.Record before sending
Save the idempotency key, request, state, and attempt time before sending. Keep this record across restarts; do not send the request if saving fails.
Log for reconciliation
Log
code,error_message, the idempotency key, and thetransfer_idif you have one, so that you can reconcile every attempt.
Common scenarios and solutions
| Scenario | Likely cause | Solution |
|---|---|---|
ACCOUNT_NOT_FOUND for an account that exists | destination_type does not match the destination account, or the account is not available to your key | Use own_account for your own accounts and another_client for other clients' accounts. Check that the account is available to the key. An account that is not available to your key is always reported as ACCOUNT_NOT_FOUND, not as AUTH_PERMISSION_DENIED. |
TRANSFER_SOURCE_NOT_ALLOWED on a transfer to another client | The source account is not your Reward Wallet | Send transfers to other clients from your Reward Wallet, listed in the Partner Personal Area under Wallet accounts. |
TRANSFER_MT_ACCOUNT_NOT_SUPPORTED | The source or destination is an MT4 or MT5 account | Use accounts on the Exness platform. |
REQUEST_INVALID_PARAMETERS on transfer creation | The idempotency key is missing or not a UUID, the source and destination are the same account, or a field has a wrong type or format | Send a random UUID in EXN-IDEMPOTENCY-KEY, use two different accounts, and check the field formats. |
REQUEST_IDEMPOTENCY_KEY_REUSED on a retry | The retry differs from the original request | Resend the original request unchanged, with the same key. |
REQUEST_IDEMPOTENCY_KEY_REUSED on a new transfer | The key was already used for another transfer | Generate a new key for every new transfer. |
The transfer stays processing | Processing takes longer than usual, or the transfer needs a manual check | Check the status again later. Transfers usually complete within a few seconds, but the processing time is not guaranteed. If it stays processing beyond your own time budget, contact Customer Support with the transfer_id. |
The transfer is rejected | The transfer was not completed | The API does not return the reason. See Transaction History in the Payments & wallet section of your Personal Area. |
| A transfer was sent to a wrong account | Wrong destination account | A transfer cannot be cancelled or reversed through the API. Contact Customer Support. |
TRANSFER_NOT_FOUND for a transfer_id you received | The key belongs to a user who is neither the sender nor the recipient of the transfer, or its scopes do not cover this transfer type | Use a key of the sender or the recipient whose scopes cover the transfer type. |
Authentication and permission checklist
For AUTH_INVALID_API_KEY and AUTH_INVALID_SIGNATURE, follow the checks in Request signing. Checks specific to the Payments API:
- For
GETrequests,EXN-IDEMPOTENCY-KEYis present with an empty value, and the signedidempotency_keyis an empty string. - For
POST /v1/transfers, the signedidempotency_keyis the same UUID as inEXN-IDEMPOTENCY-KEY. - The signed
pathcontainsaccount_idortransfer_idexactly as sent in the request path.
For AUTH_PERMISSION_DENIED, check:
- The key has the scope for the operation:
Internal transfersfor transfers between your own accounts,Partner transfersfor transfers to another client. See Payments scopes. - The request comes from a source IP that is allowed for the key.
The complete signing rules are described in Request signing.
Idempotency and recovery
After a timeout, no response, a non-API response (an HTML page, or a JSON body from a proxy or load balancer), TRANSFER_OUTCOME_UNKNOWN, SYSTEM_INTERNAL_ERROR, or SYSTEM_TEMPORARY_UNAVAILABLE, the outcome is unknown: resend the exact same request with the same idempotency key. Before every creation request, record durably that it is being sent, and send the requests of one transfer from one sender at a time.
An error on a retry after an unknown outcome does not show whether a transfer exists. Do not change the request or the key to get past it.
If you stop resending without a 201, retire the key first, so that no restart or pending resend sends it again. Then check Transaction History, and use a new key only after Customer Support confirms that no transfer was created.
The complete procedure is described in Recovery and idempotency.