Skip to main content

Core Concepts

Transfer​

A transfer moves funds between Exness accounts: from one of your accounts either to another of your own accounts, or — for authorized partners — to an account of another Exness client. The destination is always an Exness account; sending funds outside Exness is not part of this API.

  • Every created transfer is identified by a transfer_id.
  • The amount is always expressed in the currency of the source account.
Transfers cannot be reversed

A created transfer cannot be cancelled or reversed through the API. Check the destination account before sending. If a transfer was sent to a wrong account, contact Customer Support.

Destination type​

Every transfer states whose account receives the money in the required destination_type field:

ValueDestinationSource account
own_accountAnother of your own accountsAny of your supported accounts
another_clientAn account of another Exness client — a trading account on the Exness platform or a wallet. Available to authorized partners.Always your Partner Reward Wallet; any other source is rejected with TRANSFER_SOURCE_NOT_ALLOWED

destination_type must match the destination account. If you send own_account with an account that is not yours, or another_client with your own account, the API responds with ACCOUNT_NOT_FOUND — the same answer as for an account that does not exist.

Some account combinations are not supported and are rejected with TRANSFER_NOT_SUPPORTED or TRANSFER_DESTINATION_NOT_SUPPORTED. A transfer to another client can be declined by eligibility checks with OPERATION_NOT_ALLOWED.

Accounts and identifiers​

Only accounts on the Exness platform are supported. MT4 and MT5 accounts cannot be used as a source or a destination; they are rejected with TRANSFER_MT_ACCOUNT_NOT_SUPPORTED.

You needWhere to find it
Your wallet numbersPersonal Area → Payments & wallet
Your trading account numbersPersonal Area → Trading → Accounts
Your Reward Wallet numberPartner Personal Area → Wallet accounts
Trading account numbers of your direct clientsPartner Personal Area → Reports → Client accounts, or the Exness Partnership API: GET /v1/partnership/reports/clients/accounts, field client_account. Account numbers of second-level clients are masked.
An account of another Exness clientThe recipient provides the account number

Client account lists can include MT4 and MT5 accounts; transfers to them are not supported.

Identifier rules:

  • Account numbers

    Strings. Send them exactly as shown; do not convert them to numbers.

  • transfer_id

    A numeric string returned when a transfer is created. Send it back as a string, exactly as received.

API key scopes​

ScopeAllows
Internal transfersTransfers between your own accounts (destination_type: own_account), account balance, transfer status
Partner transfersTransfers from your Reward Wallet to another Exness client (destination_type: another_client), account balance, transfer status
  • A transfer creation request that is not covered by the scopes of your API key is rejected with AUTH_PERMISSION_DENIED.
  • A transfer whose type is not covered by the scopes of your API key is reported as TRANSFER_NOT_FOUND — for example, when a key with only the Internal transfers scope requests the status of a transfer to another client.
  • A transfer is readable by its sender and its recipient: by any of their API keys whose scopes cover the transfer type. Which key created the transfer does not matter — a key added after a rotation reads it too.
  • AUTH_PERMISSION_DENIED is returned only for the scopes and the allowed source IPs of the key. An account that is not available to your API key is always reported as ACCOUNT_NOT_FOUND, the same as an account that does not exist.

See Payments scopes.

Transfer lifecycle​

The creation request is processed synchronously: the response contains either the created transfer or an error. A created transfer can still be in progress; its final status is available through GET /v1/transfers/{transfer_id}.

StatusMeaningFinal
processingThe transfer is in progress. Check again later.No
doneThe money has been transferred.Yes — never changes
rejectedThe transfer was not completed. The funds are not debited from the source account, or they are returned to it.Yes — never changes
Check the transfer status

Transfers usually complete within a few seconds, but processing time can vary with load. We recommend checking the status every 2 seconds while it is processing. Keep all status requests within the request rate limit. Choose how long your integration will keep checking. Stopping these checks does not cancel the transfer.

  • The API returns the status only. For the details of a transfer that is not done, see Transaction History in the Payments & wallet section of your Personal Area.

Transfer amounts and precision​

  • Amounts are positive fixed-point decimal strings, for example "100.00", in the currency of the source account.
  • Sending more decimal places than the currency allows is rejected, not rounded.
  • When the source and destination accounts use different currencies, the amount is converted at execution. The creation response returns the amount of the transfer in the source account currency (source) and in the destination account currency (destination).

Balance​

GET /v1/accounts/{account_id}/balance returns balance — the amount available for transfers from the account, as a non-negative decimal string in the account currency, together with the account currency.

Transfer idempotency​

  • Every transfer creation requires an idempotency key in the EXN-IDEMPOTENCY-KEY header: a UUID in its canonical text form, for example 0f8fad5b-d9cb-469f-a165-70867728950e. A missing key or a key that is not a valid UUID is rejected with REQUEST_INVALID_PARAMETERS.
  • Signed GET requests send the header with an empty value, and the signed idempotency_key field is an empty string.
  • Retrying the identical request with the same key never executes the transfer twice. If the retry passes the checks of the source account, funds, limits, and eligibility, which run before the key is looked up, the API returns 201 with the same transfer_id; otherwise it returns the error from those checks, even though the transfer exists. The amounts in that response are calculated for the retry and can differ from the amounts of the transfer, for example after an exchange rate change; the transfer itself does not change. Its amounts are shown in Transaction History.
  • An identical request has the same source account, destination account, and amount. Amounts are compared as numbers, so 100 and 100.00 are the same.
  • Reusing a key with a different source account, destination account, or amount is rejected with REQUEST_IDEMPOTENCY_KEY_REUSED.
  • Idempotency keys are unique per Exness client: a key is bound to your transfer regardless of which of your API keys sent the request.
  • Idempotency keys do not expire: a key used to create a transfer stays bound to that transfer, so a retry with the same key never executes it twice, at any time.
  • Before every creation request, record durably that it is being sent. A request in flight has an unknown outcome until you record its answer.
  • While no request with the key has had an unknown outcome, any other error response of this API means that this request created no transfer.
  • Use a new key for every new transfer, including a new attempt after a transfer is rejected.
After an unknown outcome

After an unknown outcome — a timeout, no response, a non-API response, TRANSFER_OUTCOME_UNKNOWN, SYSTEM_INTERNAL_ERROR, or SYSTEM_TEMPORARY_UNAVAILABLE — resend the same request with the same key; the key stays reserved for the transfer, even after a restart of your system. Only a 201, a transfer shown in Transaction History, or Customer Support confirms the outcome.

Retire the key when you stop

If you stop sending a transfer without a 201, retire its key first: never send it again. Use a new key only for a new transfer, or after Customer Support confirms that no transfer was created. See Recovery and Idempotency.

Error model​

  • Each error response contains exactly one error with code, error_message, and description.
  • code (a stable numeric business code) and error_message (a stable <CATEGORY>_<REASON> name) are the machine-readable contract. The HTTP status describes the transport layer.
  • description is a short human-readable hint. Its text may change without notice; do not parse it.
  • Do not retry errors automatically unless the error table allows it. Some errors require you to fix the cause first. See Troubleshooting Your API Requests for retry rules and Recovery and idempotency for transfer creation.
Non-API responses

An error response of this API is a JSON body whose code and error_message are a pair from the public error codes. Any other response — an HTML page, or a JSON body from a proxy or load balancer, even one with a code — is a non-API response: it comes from infrastructure between you and the API and says nothing about the outcome of your request. Treat it as no response.

Rate limits​

When you exceed a request quota, the API responds with REQUEST_RATE_LIMIT (HTTP 429). Wait before sending another request.

Guides · Troubleshooting Your API Requests · API Reference