Transfer to another of your accounts, or to another business
/transfersdestination is one of:
own_account+accountId— another of your own accounts (acc_…fromGET /accounts), in the same currency. Free of charge. A sub-merchant's account is not your own. The source itself is400 destination_is_source; an account that is not yours is404 not_found; another currency is400 currency_mismatch.business+ exactly one ofemail(the business owner's) ormerchantNumber(its ten-digit number, asGET /mereports it). The money lands in that business's primary account in the currency. The transfer fee is charged on top and reported infee. Whatever the reason a business does not resolve — no such business, it cannot receive, no account in the currency, an owner e-mail shared by several businesses — the answer is one:400 destination_not_found, so the endpoint cannot be used to learn who banks here. Itsdetailis one text for every reason, and points atPOST /payouts— an individual is paid with a payout. Your own business is400 destination_is_self. An API key whose destinations keep failing to resolve is refused with429 destination_lookup_limitedfor the rest of the window. AmerchantNumbercarries a check digit; a mistyped one is400 validation_failedwithout a lookup.
sourceAccountId may be left out: your default account in the currency (isDefault: true on
GET /accounts) is debited — or the only one, when you hold just one. None is 400 no_account_for_currency.
Always 202. Most transfers settle inside the request and read completed; one that has not settled yet
reads pending — poll Location. The transfer is the ledger's own entry: its id is the txn_… id
GET /accounts/{accountId}/transactions shows for the debit. There is no step-up and no approval step for
API transfers; the signed key is the authentication.
A refusal (insufficient_funds, limit_exceeded, …) is a 400 with its own code. It
does not use up the merchantReference: once refused, the reference may be sent again with a new
Idempotency-Key. A refusal made after the transfer was recorded leaves a
failed entry in the ledger under the reference; at most one transfer under a reference is ever not
failed. A 500 is never a refusal: retry with the same Idempotency-Key and you get the transfer as it
stands, never a second one — or look the reference up with GET /transfers?merchantReference=, which finds
the transfer if it was made. A request left unanswered and not retried for 15 minutes is settled by the
platform: answered with the transfer if one was made, otherwise refused with 400 request_not_executed — nothing
moved, its merchantReference is free again, and a retry under the same key gets that answer, so send it again
under a new one. The same Idempotency-Key with a different request is 400 idempotency_key_reused, however
long after. Requires transfers:write.
Parameters
Idempotency-KeystringheaderrequiredClient-generated unique key for this logical request (UUID recommended). See Idempotency.min length 1 · max length 255
X-Request-IdstringheaderOptional client correlation id; echoed back unchanged.max length 128
Request body application/jsonrequired
merchantReferencestringrequiredYour own unique reference for this transfer; reusing it under a newIdempotency-Keyis400 duplicate_merchant_reference.min length 1 · max length 100
amountobjectrequiredWhat the destination is credited. A fiat currency; no more decimals than it has.valuestringrequiredExample:
149.90pattern ^-?\d{1,18}(\.\d{1,18})?$
currencystringrequiredISO 4217 code for fiat (EUR), asset ticker for crypto (USDT).Example:
EURpattern ^[A-Z0-9]{3,10}$
destinationTransferDestinationrequiredown_accountwithaccountId, orbusinesswith exactly one ofemailandmerchantNumber. On the resource: the type, and forown_accounttheaccountId. A business's e-mail or number is not kept, and its account is never shown;counterpartyNameon the ledger entry says who received it.typestringrequiredAllowed values:
own_accountbusinessaccountIdstringOpaque account identifier. Treat as a string; never parse or construct it.Example:
acc_AAAAAAAAAAcpattern ^acc_[A-Za-z0-9_-]{11}$
emailstring (email)The receiving business's owner e-mail.max length 254
merchantNumberstringThe receiving business's merchant number (GET /me→merchantNumber).pattern ^[0-9]{10}$
sourceAccountIdstringOptional. Left out, your default account in the currency (isDefault) — or the only one.Example:
acc_AAAAAAAAAAcpattern ^acc_[A-Za-z0-9_-]{11}$
descriptionstringmax length 140
Responses
Transfer accepted. The code is always 202 — read status: completed or failed is final;
pending means it has not settled yet, so poll Location — Retry-After is sent only then. An
idempotent replay returns this original body.
Headers
Locationstring (uri-reference)The resource URL to poll for the current state (RFC 9110 §15.3.3 status monitor).Retry-AfterintegerSeconds to wait before pollingLocation. On a202it is present only while the body'sstatusis not yet terminal — its absence is a second signal that the work is already done.X-Request-IdstringThe client'sX-Request-Idif supplied, otherwise a server-generated id. EqualstraceIdin problems.Idempotent-Replayedbooleantruewhen this response was replayed from an earlier request with the sameIdempotency-Key.RateLimit-LimitintegerRateLimit-RemainingintegerRateLimit-ResetintegerSeconds until the window resets.
Schema application/json
objectstringrequiredAllowed values:
transferidstringrequiredThe ledger id of the transfer's debit — the same entryGET /accounts/{accountId}/transactionsshows.Example:
txn_AAAAAAAAB3Ypattern ^txn_[A-Za-z0-9_-]{11}$
merchantReferencestringAbsent on a transfer made in the portal.statusstringrequiredpendingaccepted, not settled yet ·completedsettled ·failedrefused, rejected or expired — no money moved.Allowed values:
pendingcompletedfailedamountMoneyrequiredDecimal amount as a string — never a float, never minor units. An amount you send may carry no more decimal places than its currency has (and never more than 8); trailing zeros do not count, so10.100 EURis fine and10.123 EURis400 validation_failedonamount.value.valuestringrequiredExample:
149.90pattern ^-?\d{1,18}(\.\d{1,18})?$
currencystringrequiredISO 4217 code for fiat (EUR), asset ticker for crypto (USDT).Example:
EURpattern ^[A-Z0-9]{3,10}$
feeobjectrequiredCharged on top ofamount; zero between your own accounts.valuestringrequiredExample:
149.90pattern ^-?\d{1,18}(\.\d{1,18})?$
currencystringrequiredISO 4217 code for fiat (EUR), asset ticker for crypto (USDT).Example:
EURpattern ^[A-Z0-9]{3,10}$
totalDebitedobjectrequiredWhat leaves the source account:amount + fee.valuestringrequiredExample:
149.90pattern ^-?\d{1,18}(\.\d{1,18})?$
currencystringrequiredISO 4217 code for fiat (EUR), asset ticker for crypto (USDT).Example:
EURpattern ^[A-Z0-9]{3,10}$
sourceAccountIdstringrequiredOpaque account identifier. Treat as a string; never parse or construct it.Example:
acc_AAAAAAAAAAcpattern ^acc_[A-Za-z0-9_-]{11}$
destinationTransferDestinationrequiredown_accountwithaccountId, orbusinesswith exactly one ofemailandmerchantNumber. On the resource: the type, and forown_accounttheaccountId. A business's e-mail or number is not kept, and its account is never shown;counterpartyNameon the ledger entry says who received it.typestringrequiredAllowed values:
own_accountbusinessaccountIdstringOpaque account identifier. Treat as a string; never parse or construct it.Example:
acc_AAAAAAAAAAcpattern ^acc_[A-Za-z0-9_-]{11}$
emailstring (email)The receiving business's owner e-mail.max length 254
merchantNumberstringThe receiving business's merchant number (GET /me→merchantNumber).pattern ^[0-9]{10}$
descriptionstringfailureobjectPresent whenstatusisfailed.codestringrequiredThe code the refusal was answered with.messagestringrequired
createdAtstring (date-time)requiredRFC 3339, UTC, with millisecond precision.Example:
2026-09-18T10:15:30.123ZupdatedAtstring (date-time)requiredRFC 3339, UTC, with millisecond precision.Example:
2026-09-18T10:15:30.123ZcompletedAtstring (date-time)RFC 3339, UTC, with millisecond precision.Example:
2026-09-18T10:15:30.123Z