Reference

Changelog

Notable changes to the External API and to these docs. Most recent first. Subscribe to webhooks and watch this page to stay ahead of deprecations.

Versioning policy

The API is versioned in the path (/v1). Breaking changes ship under a new version — the current version keeps working. Deprecations are announced here and remain supported throughout a transition window before removal.

Within a version, changes are additive: we may introduce new fields and new enum values without a version bump. Build consumers to tolerate that.

To stay forward-compatible: branch your logic on the stable error type — never on message text — ignore unknown fields rather than rejecting them, and treat any unrecognised enum value as a safe default instead of failing.

Releases

A Brazilian real deposit method can now be a Pix collection account — depositType: "PIX" no action needed 2026-09-10

The account-level receive details of a Brazilian real (BRL) deposit method may now come back as depositType: "PIX". No other currency returns this shape.

  • What changes — a Brazilian real (BRL) deposit method can now return depositType: "PIX" with two fields: qrCodeString, the copy-and-paste code the payer pastes into their bank app, and base64QRCode, the same code rendered as a PNG.
  • Brazilian real deposit methods can now be created on demandPOST /v1/deposits/methods with methodType: "fiat" accepts currency: "BRL", alongside EUR, USD, GBP, MXN and ARS. It previously answered a validation error naming currency.
  • base64QRCode is raw base64, with no data-URI prefix — prepend data:image/png;base64, yourself before using it as an image source.
  • It carries no amount and no referenceCode — the payer enters the amount in their bank app, and the code carries a reference dedicated to this collection account, so there is no separate reference field to show. Do not require either field on this variant.
  • Pass qrCodeString through unchanged — the code carries its own checksum over its exact characters, so re-encoding it, trimming it or inserting line breaks makes the payer’s bank app reject it as corrupt. Show it as copyable text and render the image from base64QRCode.
  • What does not change — every other depositType on the account view behaves exactly as before, and a deposit method whose details are not payable yet still reads as PENDING.
  • What to do — nothing, unless you switch exhaustively on depositType and reject unknown values; then add a PIX arm, or fall through to a default instead of failing.

Brazilian real collections have a rail value of their own — PIX no action needed 2026-09-10

A Brazilian real (BRL) collection can now be quoted and reported on the rail PIX, alongside the PIX_BR spelling that already existed. Both are accepted; neither replaces the other.

  • Where the new value appearsoriginRail on POST /v1/quotes, and rail on the deposit object returned with a deposit or an order.
  • What the two values meanPIX names the instrument the collection is actually provisioned as, the copy-and-paste code and QR the payer pays (depositType: "PIX"). PIX_BR names the payment scheme. A BRL quote carrying either value is accepted, and quotes you already send keep working unchanged.
  • Discover the rails, do not hardcode themGET /v1/currencies/BRL/payin-schema lists every accepted spelling under acceptedOriginRails and the canonical one to send under payinMethods. Read it instead of pinning a literal, so a corridor that gains a rail does not turn into a validation error on your side.
  • The Brazilian Pix method now reports its own channel typepayinMethods[].type on that same endpoint reads pix for the Pix method, where it previously read bank. Label it as Pix: the payer pastes a code into their bank app and is never given an account number to transfer to. The Brazilian bank-transfer method still reads bank.
  • Treat rail values as an open set — corridors gain rails without a version bump. If you switch exhaustively on a rail and reject unknown values, add a PIX arm, or fall through to a default instead of failing.
  • What to do — map PIX to the Pix copy-and-paste instruction (depositType: "PIX", carrying qrCodeString and base64QRCode) exactly as you would for PIX_BR. Nothing else about the Brazilian corridor changes.

A pending payin instruction can now say that waiting will never produce details — pendingReason: "accountless_per_account_corridor" action required 2026-09-10

pendingReason on a depositType: "PENDING" payin instruction has a second value.

  • New valueaccountless_per_account_corridor. It means this corridor collects only into a collection account dedicated to the paying account, the request named no account, and none can be created for it.
  • Waiting does not resolve it — unlike collection_account_activating, payable details will never follow for this instruction and no activation webhook will arrive for it. Polling it is an endless loop.
  • What to do — create the deposit against an account and read the instruction from that response. Treat this value as terminal for the instruction you are holding, and surface it rather than showing the payer a spinner.

A Colombian peso deposit method can now return a payment page instead of bank coordinates action required 2026-09-10

On POST /v1/deposits/methods, GET /v1/deposits/methods and GET /v1/deposits/methods/{methodId}, the depositInfo of a COP method may now arrive as depositType: "PSE" carrying a single url, where it previously always carried bank coordinates.

  • Handle PSE on depositInfo — the object is { "depositType": "PSE", "url": "..." } and nothing else: no account number, no bank name, no reference. Present the url as a link the payer opens; there is nothing on it to copy into a bank transfer.
  • Existing methods are unaffected — a COP method that returns bank coordinates today keeps returning them, with every field intact. The payment-page shape appears only on methods whose collection account is set up for it.
  • New optional fieldamountPrefilled on a PSE instruction. When true the page already carries the amount and the payer cannot change it; when false or absent, the payer enters the amount themselves and you must tell them what to pay.
  • Read the type, not the currency — branch on depositInfo.depositType rather than assuming a shape from currency. A currency can serve more than one instruction type, and which one you get can change without a version bump.

US dollar bank payouts — say whether the account is checking or savings no action needed 2026-09-10

An ACH_US destination now takes an optional bankAccountType, which says what kind of bank account receives the money. The US banking network carries it on the payout, and until now we could not tell it apart, so every US payout was sent as a checking account.

  • Optional, and it defaults — omit bankAccountType and the payout is sent as CHECKING, which is what happened before this field existed. Nothing you already send needs to change.
  • Accepted valuesCHECKING or SAVINGS, in capitals. Any other value is rejected with a validation error rather than quietly treated as a checking account.
  • Not the same field as accountTypeaccountType (PERSONAL / BUSINESS) says whether the recipient is a person or a business. bankAccountType says what kind of bank account the money lands in. Both can be sent on the same destination.
  • Confirm the field list at runtimeGET /v1/currencies/USD/destination-schema?method=achUS returns every field, whether it is required, and its accepted values.

US dollar bank payouts — state is now required action required 2026-09-09

An ACH_US destination now requires state, the two-letter code of the recipient’s US state. It was previously not part of the destination; a request that omits it, or sends anything other than a two-letter code, is rejected with a validation error.

  • Now requiredstate, on every ACH_US destination you create. This rail also needs city and postalCode. Each of those two is accepted on the destination, or on the recipient’s details — the destinationUserData you send when the recipient is new, or the details we already hold for one you have used before.
  • Accepted values — exactly two uppercase letters, for example NY or CA. A state name such as New York, or an empty string, is not accepted.
  • What to do — add state wherever you build an ACH_US destination, for example on POST /v1/orders and POST /v1/withdrawals. US destinations you already stored keep working on read; an order to a stored recipient whose state we do not hold is rejected when you create it on POST /v1/orders. For a recipient you have used before, sending state in destinationUserData does not lift that — update the destination, or the recipient’s details, with the state.
  • That rejection is now a 400 — an order to a stored recipient whose state we do not hold returns invalidParameters (id 1008) with HTTP 400, naming the field. It previously returned errorCreatingOrder (id 1021) with HTTP 500. If you retry on 5xx, stop retrying this case and supply the state instead.
  • Confirm the field list at runtimeGET /v1/currencies/USD/destination-schema?method=achUS returns the required fields and their formats. Read it instead of hardcoding this list, and it will stay correct through later changes.

Colombian peso payouts — BANK_DEPOSIT_COL now needs the bank code and the recipient’s ID action required 2026-09-08

A BANK_DEPOSIT_COL destination previously took a recipient name, a payout network id and an account number. The Colombian payout rail needs six fields, so that shape was accepted at creation and then refused at payout. Creating or updating one now requires all six, and each missing field is named in the validation error.

  • Now requireddestinationBankCode (four digits, and one of the codes on the supported bank list, e.g. 1007 Bancolombia), destinationBankAccountType (CORRIENTE or AHORRO), destinationDocumentType (CC, CE, NIT, TI or PP) and destinationTaxId, alongside destinationName and destinationBankAccount.
  • No longer requireddestinationNetworkId. It is now optional and is not used to route the payout. If you were sourcing it from GET /v1/currencies/COP/networks just to satisfy the schema, you can stop.
  • A bank code that is not on the list is refused at creation — a three-digit code, or a bank name where the code belongs, returns a 400 naming the field. Previously such a value was accepted, the funds were collected, and only then did the payout fail.
  • Destinations you already stored keep working on read — an existing Colombian recipient still reads, still lists and still appears on past orders, with every field intact, and you can still rename it. Supply the four fields when you next create or update one; until then it cannot fund a new payout.
  • BANK_DEPOSIT_COL and ACH_COP are equivalent — same payout rail, same six fields, same bank list. They differ only in the key that carries the account number (destinationBankAccount here, destinationBankAccountNumber on ACH_COP). Use ACH_COP for new integrations: the name BANK_DEPOSIT_COL is also used for a Colombian collection rail, so the same string means two different things depending on where it appears.
  • Confirm the field list at runtimeGET /v1/currencies/COP/destination-schema?method=bankDepositCOL returns the required fields, their formats and the accepted bank codes. Read it instead of hardcoding this list, and it will stay correct through later changes.

A pending payin instruction can now tell you why it is pending no action needed 2026-09-03

A payin instruction with depositType: "PENDING" may now carry an optional pendingReason. It is additive: nothing that exists today changes shape, and the field is simply absent when we cannot classify the reason.

  • New optional fieldpendingReason on a PENDING payin instruction. Today the one value is collection_account_activating, which means the collection account for this payer is being opened and payable details are expected shortly.
  • A missing value never tells you the wait is short or long — absence means only that no reason is classifiable. Do not infer timing from a missing field.
  • It also appears on webhooks — the field rides the deposit instruction wherever it is returned, including webhook payloads. If you validate webhook bodies with a strict parser of your own, allow the new key.
  • Only on the transaction-level instruction — an account-level deposit method never carries this field at all, whatever its status.
  • Expect more values over time — treat pendingReason as an open set and ignore values you do not recognise rather than failing on them.

Peruvian sol bank payouts — destinationCCI is now required action required 2026-09-02

A BANK_DEPOSIT_PEN destination now requires destinationCCI. It was previously optional; a request that omits it, or sends it empty, is rejected with a validation error.

  • Now requireddestinationCCI, alongside the fields you already send. Send it for every recipient, whichever bank they use.
  • Accepted values — digits only, 1 to 20 characters. An empty string is no longer accepted.
  • What to do — add destinationCCI wherever you build a BANK_DEPOSIT_PEN destination, for example on POST /v1/orders and POST /v1/withdrawals. Peruvian destinations you already stored keep working on read; supply the CCI when you next create or update one.
  • Confirm the field list at runtimeGET /v1/currencies/PEN/destination-schema?method=bankDepositPEN returns the required fields, their formats and their accepted values. Read it instead of hardcoding this list, and it will stay correct through later changes.

Colombian ACH payouts — the bank code is checked against the bank list action required 2026-09-01

On an ACH_COP destination, destinationBankCode must be one of the four-digit codes the Colombian ACH rail publishes. Any other value is now rejected with a validation error naming the field; previously any non-empty string was accepted.

  • What changes — the code must be exactly four digits and a bank on the supported list (e.g. 1007 Bancolombia, 1001 Banco de Bogotá). A three-digit code such as 001, or a bank name where the code belongs, is refused.
  • Why — those values were accepted at creation and then refused by the payout rail, after the funds had been collected, leaving the payment in manual review. The check now happens at the boundary, so you get a 400 instead of a stuck payment.
  • What does not change — Colombian BRE_B_COP payouts carry no bank code and are untouched, as are all other rails. An ACH_COP destination you created before this date still reads, lists and appears on orders exactly as before, bank code included, even if its code is not on the list — only creating or updating one is held to the new rule.
  • What to do — send the four-digit code, not the bank name. GET /v1/currencies/COP/destination-schema?method=achCOP returns the accepted codes with their bank names; read it instead of hardcoding the list. If one of your stored destinations carries a code that is no longer accepted, replace it before your next payout — the rail would refuse it.

A rail that is not a collection method for the currency now returns 1008 instead of 1002 action required 2026-09-01

When you send a supported currency together with a rail that the currency is not collected on, the rejection now identifies the real problem — the currency/rail pairing — instead of reporting the currency as unsupported. Affects POST /v1/deposits and POST /v1/orders. The status stays 400.

  • What changes — the response for this case carries error: "ValidationError", errorId: 1008, errorName: "invalidParameters". It previously carried errorId: 1002, errorName: "notSupportedCurrency" and a message listing currencies that were unrelated to your request. The new message names the currency and the rail you sent, and the collection methods the corridor does accept.
  • What does not change — the request is still rejected, and it was correctly rejected before: these pairings are not available. Nothing new is accepted. A currency that genuinely has no enabled corridor still returns errorId: 1002 / notSupportedCurrency, unchanged — the two rejections are now distinguishable, which they were not before.
  • What to do — if you branch on errorId: 1002 to mean “this currency is unsupported”, that branch will no longer be entered for a currency/rail mismatch; handle 1008 for it, and treat it as a request to fix rather than a currency to drop. Call GET /v1/currencies and read payinMethods to discover the rails each currency is collected on.

Deposits take originNetworkId to choose the mobile-money collection network action required 2026-09-01

POST /v1/deposits accepts a new optional originNetworkId, and a mobile-money collection that needs the payer's network now answers 400.

  • What changes — you may send originNetworkId, one of the id values from GET /v1/currencies/{currency}/networks?rail={rail}&rampType=deposit, passing the same rail you send on the deposit. An id that corridor does not publish is rejected with 400, and so is an originNetworkId sent on a rail that is not mobile money.
  • What changes — where a mobile-money collection offers more than one network and you send no originNetworkId, the response is 400 naming the field. It used to be 500: do not retry it, resend with a network.
  • What does not change — the field is optional. Omit it and every request you send today is accepted unchanged; a collection with one network still resolves it for you.
  • What to do — nothing, unless you collect by mobile money; then read the networks for the currency and send the payer's choice as originNetworkId.

Argentine peso (ARS) is now a supported fiat currency for POST /v1/deposits/methods no action needed 2026-08-31

  • What changesPOST /v1/deposits/methods with methodType: "fiat" now accepts currency: "ARS".
  • What does not change — every other supported fiat currency, and every existing request, behaves exactly as before.
  • What to do — nothing, unless you want to provision a dedicated ARS receiving account on demand; then send currency: "ARS" with methodType: "fiat".

Argentine peso bank payouts — the recipient tax ID is now required action required 2026-08-29

A BANK_DEPOSIT_AR destination must carry destinationTaxId: the recipient's CUIT/CUIL. It was optional; a request that creates an AR destination without it is now rejected with a validation error naming the field.

  • Now requireddestinationTaxId, format ^\d{2}-?\d{8}-?\d$ (e.g. 20-30405060-7), alongside destinationName, destinationNetworkId and destinationBankAccount.
  • Where — wherever you send a BANK_DEPOSIT_AR destinationTransferData inline: POST /v1/orders and POST /v1/withdrawals. Destinations saved through the app are held to the same rule.
  • Why — the payout is registered against the recipient's own tax ID. Previously an AR destination without one could be registered under the payer's tax ID; that fallback is gone, and an empty value is now refused at capture instead of failing later at payout.
  • What does not change — AR destinations you created before this date keep reading, listing and appearing on orders unchanged. Editing one requires adding the CUIT/CUIL; paying out from one without it is refused by the rail and routed to manual review, never re-attributed.
  • Confirm the field list at runtimeGET /v1/currencies/ARS/destination-schema returns the required fields and their formats. Read it instead of hardcoding this list.

Withdrawals can declare a third-party destination with beneficiary no action needed 2026-08-28

POST /v1/withdrawals accepts a new optional beneficiary object for payouts to a wallet that is not the account holder's own.

  • What changes — you may send beneficiary with name, surname and relationship: "third_party". When present, both name and surname are required.
  • What does not change — omit beneficiary and the withdrawal behaves exactly as before. Every existing request is accepted unchanged.
  • What to do — nothing, unless you pay out to a third party's wallet; then send beneficiary with the recipient's real name and surname.

The withdrawal approval endpoint has been removed action required 2026-08-28

POST /v1/withdrawals/approve no longer exists.

  • What changesPOST /v1/withdrawals/approve now returns 404. Withdrawals created through the API were never held for this approval step.
  • What to do — if you call this endpoint, remove that call. A created withdrawal proceeds without it.

KYC profile: pep is replaced by pepDeclaration, and profession is a sector code action required 2026-08-20

Two fields on POST /v1/kyc/data change. Requests keep succeeding either way — no new error is returned — but a value we no longer recognise is not recorded.

  • What changespep (boolean) is removed. Send pepDeclaration instead, with one of no, yes, family (immediate family member of a politically exposed person) or related (known close associate of one). Omit the field when the holder has not answered; never send no to mean unanswered.
  • What changesprofession is now an activity sector code, a short numeric code such as 24. Free text such as "Nurse" is still accepted by the request but is not recorded: it counts as not declared, and the holder is asked to choose a sector while completing verification.
  • What to do — if you send pep, switch to pepDeclaration: pep is now ignored, so a declaration sent under the old key is not stored. If you send a free-text profession, either send a sector code or omit the field. Both fields stay optional, and missingFields in the response tells you what is still outstanding.

Orders now return externalReference under the name you send it no action needed 2026-08-18

You set externalReference when creating an order. Until now the order read back carried that value under a misspelled key, externalRefeference, with a doubled e.

  • What changesGET /v1/orders and GET /v1/orders/{orderId} now return externalReference with the value you supplied. Reconciling on the key you wrote with works.
  • What does not change — on GET /v1/orders, externalRefeference is still returned with the same value. It is now marked deprecated in the spec and will be removed in a future major version.
  • AlsoPOST /v1/orders now echoes externalReference on the create response, so you can confirm what you sent without a second call. The correct spelling is returned on GET /v1/orders, GET /v1/orders/{orderId}, POST /v1/orders and POST /v1/pending-payments/{transferId}/create-order; the deprecated key was never present on the create or single-order responses and is not being added there.
  • What to do — nothing today. When convenient, switch your reads to externalReference; if you branch on the presence of externalRefeference, note that both keys are present.
  • Corridor discovery returns 503 when a lookup is unavailable action required 2026-08-18

    GET /v1/currencies/{currency}/networks and GET /v1/currencies/{currency}/limits now tell an empty answer apart from an answer they could not obtain.

    • What changes — when the lookup behind either endpoint is temporarily unavailable, you get 503 with error: "ExternalServiceError". Previously both returned 200 — an empty networks array, or limits: null.
    • What does not change — a successful response is identical. An empty array still means the corridor genuinely has no matching networks, and limits: null still means no bounds are published for it.
    • What to do — handle 503 on both endpoints by retrying. If you cache either result, only cache a 200: an empty list is settled, a 503 is unknown.

Collections in ARS, COP, CLP, BOB and TWD are no longer available action required 2026-08-07

These five currencies can no longer be used as the origin of a quote or an order — you cannot collect funds in them. Paying out to all five is unchanged and continues to work.

  • What changesPOST /v1/quotes and POST /v1/orders reject originCurrency of ARS, COP, CLP, BOB or TWD with a validation error naming the currency.
  • What does not changedestinationCurrency still accepts all five. Payouts, destination schemas and existing payout methods are untouched.
  • What to do — stop offering these five as collection currencies. Orders already created are unaffected.
  • Check availability at runtimeGET /v1/currencies returns what each currency can do today. Read it instead of hardcoding a list, and it will stay correct through later changes.

Chilean peso bank payouts — three fields are now required action required 2026-08-07

A BANK_DEPOSIT_CL destination now takes five fields. Three of them were previously optional and are enforced today — a request that omits any of them is rejected with a validation error.

  • Now requireddestinationBankName, destinationBankAccountType and destinationTaxId, alongside the destinationName and destinationBankAccount you already send.
  • Accepted valuesdestinationBankAccountType is CORRIENTE or AHORRO. destinationTaxId is the recipient's RUT.
  • What to do — add the three fields wherever you build a BANK_DEPOSIT_CL destination, for example on POST /v1/orders and POST /v1/withdrawals.
  • Confirm the field list at runtimeGET /v1/currencies/CLP/destination-schema returns the required fields, their formats and their accepted values. Read it instead of hardcoding this list, and it will stay correct through later changes.

Unreleased 2026-08-13

  • New: fetch a single conversationGET /v1/conversations/{conversationId}?endUserEmail= returns one conversation. Previously you had to list an end-user's conversations and pick it out. endUserEmail is required: a conversation is addressed by end-user and id. Additive — nothing you send today changes.
  • Unrecognised query parameters are now rejected on the list endpoints — /v1/deposits, /v1/orders, /v1/withdrawals, /v1/pending-payments and their /count variants. A misspelled filter such as ?limitt=5 previously returned 200 with the parameter ignored; it now returns 400. If you send any parameter not listed for the endpoint, remove it.
  • city and postalCode are required when paying out to SEPA, ACH_US or GBP_BANK_TRANSFER. Send them in either destinationTransferData or destinationUserData — either location satisfies the requirement. Requests missing both are now rejected at submission with a 400 naming the field, instead of failing later during payout.
  • Clearer payout errors. A missing recipient address now returns a message naming the field and where to put it, rather than a generic "user data is not valid".
  • New: refundStatus on pending payments. GET /v1/pending-payments and GET /v1/pending-payments/{transferId} may now return refundStatus — one of pending_approval, returning, returned, failed. The field is absent when no refund is in progress. Only returned means the payer has the money back: do not read returning as complete. While the field is present the payment cannot be linked to an order or a deposit, so stop offering it for linking. Additive — nothing you send today changes.

v1.0.0 current 2026-07-06

Initial public API (quotes, orders, deposits, withdrawals, webhooks) on stable JSON contracts — and the launch of this documentation site.

AreaChange
quotesLock an exchange rate and fees for a currency pair.
ordersCommit a quote to a payout destination and track it to completion.
depositsCollect funds locally into a workspace balance.
withdrawalsPay out locally from a workspace balance.
KYCOnboard and verify entities before they transact.
webhooksSigned event notifications for state changes.
discoveryPer-currency capability discovery via /v1/currencies/*.
banking accountsManage the banking accounts behind deposits and withdrawals.
docsModern API documentation launched — this site.

Deprecated — the generic LOCALBANK deposit type is deprecated in favour of corridor-specific types (e.g. SEPA, PIX, and country-specific bank types). Discover the exact type per currency with GET /v1/currencies/{currency}/payin-schema. It is still returned on historical records for backward compatibility.

Upcoming

A cleaner, more consistent contract is planned: prefixed resource ids, a unified error envelope, 429 rate limiting with Retry-After, and standardized timestamps. It will ship under the versioning policy above — existing /v1 contracts keep working, and every change lands on this page first.

← Prev
Glossary