Use the sandbox for development. All examples in these guides work against
https://api.sand.etherfuse.com. If you have not set up your sandbox account, see Initial Setup./ramp prefix. Send your API key in the Authorization header with no Bearer prefix. See Authentication.
Payment accounts, quotes and orders belong to an organization, and their routes start with /organization/{organizationId}. Webhook subscriptions belong to the organization that owns the API key. See Organizations in the route.
Conventions
Organizations in the route
Payment account, quote and order routes take the organization the call acts for as{organizationId}, for example POST /organization/{organizationId}/payment_account.
- Use your own organization’s id, from
GET /me, to act for yourself. - Use a customer organization’s id to act for that customer. You get it when you create the organization with
POST /organization, or fromGET /organizations. - Your API key can act for its own organization and for its direct customer organizations. Any other id returns
404not-found. - A quote under a customer organization can use that customer’s payment accounts and your own organization’s. For example, quote from your business bank account to the customer’s wallet. A quote cannot use another customer organization’s account. The quote and its order belong to the organization in the route, not to the organization that holds an account. The order’s
organizationId,GET /ordersfiltered byorganizationId, and reporting all show the order under that organization, so use the organization you want the order reported under.
GET /orders stay at the partner level and do not take an organization id. One subscription covers your organization and every customer organization. GET /orders lists the orders of your organization and all its customer organizations.
The flow
1
Register payment accounts
A payment account is a bank account or a wallet that money moves from or to. Register each one with A wallet sends only The
POST /organization/{organizationId}/payment_account.A bank account states its market with country and currency, and its identifier in accountDetails:accountDetails of kind address, with its chain:accountDetails.kind decides which fields accountDetails carries:A missing field or an extra one returns
400 validation-error, with one entry per field in errors.Registration info. A bank account route requires holder details such as accountHolderName and taxId, and some routes need more. We fill each field from the verified identity of the organization in the route when we hold it. To register a customer’s bank account, pass the customer’s organization id. When a required field is still missing, the request returns 422 registration-info-required:required lists every field the route needs and missing lists the ones you still have to send. Both are JSON Pointers into your request. Add the missing fields under registrationInfo and send the request again. A taxId you send must match the verified one, or you get 422 holder-tax-id-mismatch. You can also send every registration field you have: we check each value’s format and ignore the fields this route does not use. To see the lists before you register, call GET /organization/{organizationId}/payment_account/requirements.A new registration returns 201. Registering the same account again returns the account the organization already holds, with 200. If another organization holds the account, you get 409 payment-account-unavailable.A new account starts pending. We register it with the payment provider, then move each rail direction to ready or rejected. The account’s status becomes ready when any direction is ready, and rejected when every direction is rejected. To retry a rejected direction, fix the details (usually registrationInfo) and register the same account again. We send it to the provider again, and the direction goes back to pending.2
Check the account's rails
The response lists the rails the account can move money on, keyed by rail. Each rail reports the account’s readiness per direction:
source for money leaving the account, destination for money arriving.- A direction’s
statusispending,ready,rejectedordisabled. You can quote a direction only when it isready. - A
rejecteddirection also hasrejection: acodeyou can branch on and amessageyou can show your customer. SeeRegistrationRejectionCodein the payment account reference. - A direction is
nullwhen the rail cannot carry money that way for this account. minAmountandmaxAmountappear when the rail has a known limit.isDefaultmarks the rail a quote uses when you do not name one.
paymentAccountUpdated to hear when a direction becomes ready, or read the account again with GET /organization/{organizationId}/payment_account/{id}.3
Get a quote
Price a transfer between two registered accounts with Take each side’s asset from
POST /organization/{organizationId}/quote. Each account must belong to the organization in the route or to your API key’s organization. One side must be a wallet: fiat to crypto, crypto to fiat, a same-chain swap, or the same token sent to another chain.GET /supported_assets: a market’s asset (its currency code) for a fiat side, a token’s asset for a crypto side. Pass paymentAccountId to list only what one account can send or receive.The quote returns sourceAmount, destinationAmount, the rails each side uses, rateBeforeFees, rateAfterFees, the total fee as feeBps and feeAmount, and the fee lines in fees[]. Each fee line has a type (transactionFee, partnerFee, walletSponsor or bridge), an amount and an asset. Quotes that convert between currencies also return midMarketRate. The order created from the quote returns the same fee lines.A quote expires 2 minutes after it is created (expiresAt). Your organization must be approved to quote, or you get 409 organization-not-approved.4
Create the order
Create the order with
POST /organization/{organizationId}/order and the quoteId. The response is 201 with the full order. The order’s id is the quoteId.Sending the same quoteId again returns the existing order with 200, even after the quote has expired. Retry a timed-out request with the same quoteId and you never create a second order. See Idempotency.fundingInstructions tells the customer how to fund the order: the rail, our reference for the order when it is funded from a bank (spei or pix), and a fundingDeadline. An order with no funds by the fundingDeadline moves to canceled. You can also cancel an unfunded order yourself with POST /organization/{organizationId}/order/{id}/cancel. It answers 202 with the order before the cancel, and the order moves to canceled a few seconds later. fundingInstructions.destination holds where to send the funds (a CLABE on spei, a BR Code on pix, an address on a chain). It is absent until it is available. Subscribe to orderUpdated to receive the order when it arrives, or read the order again with GET /organization/{organizationId}/order/{id}.If a funding destination expires before the customer pays, call POST /organization/{organizationId}/order/{id}/funding_instructions/refresh. To cancel an order before it is funded, call POST /organization/{organizationId}/order/{id}/cancel.5
Track the order
An order’s
status is one of:orderUpdated delivers the full order on each status change. See Webhooks.Authorization. Some transfers need the account holder’s approval before money moves, for example an offramp from an embedded wallet or the claim into one. The order’s authorization then holds what to sign, and the status does not change while it waits. Sign authorization.method.message and send it with POST /organization/{organizationId}/order/{id}/authorization. authorization is null when nothing is needed.Quote types
The two payment accounts decide the type of transfer. You do not send a type. Quote any asset to any other asset between two payment accounts: if we support the route, the quote returns a price, and if we do not, it returns an error that says why.
A cross-chain transfer works between the chains in the token’s
bridgeDestinations on GET /supported_assets. A quote to any other chain fails with 422 unsupported.
Rails
A rail is the network that moves the money. A bank account moves on a fiat rail (spei for MXN, pix for BRL). A wallet moves on its chain (stellar, solana, base, polygon, monad or avalanche). Each account’s rails map shows which rails it can use and in which direction. Name a rail in the quote with sourceRail or destinationRail, or leave it out to use the account’s default rail.
Each chain has its own asset identifier format and setup. See the chain guides: Solana, Stellar, Base, Polygon, Monad, Avalanche.
KYC status
Your customers complete KYC before they transact. See the KYC overview for the flows. Read a customer’s KYC status withGET /organization/{organizationId}/kyc, and a business’s KYB status with GET /organization/{organizationId}/kyb. To hear when it changes, subscribe to kycUpdated with POST /webhook_subscription. See the kycUpdated payload.
Fees
Entering a stablebond is free, and leaving one costs 5 bps. A trade that crosses currencies pays that market’s volume-based FX fee, and a trade between two markets pays the higher of their FX fees. Partner, wallet setup and bridge fees may also apply. Every quote and order itemizes fees infees[]. See Transaction Fees.
Sandbox
In sandbox,POST /organization/{organizationId}/order/{id}/fiat_received simulates the fiat deposit for an order funded from a SPEI or PIX account, so you can test an onramp without sending money. See the Sandbox Reference.
Resources
The API manages these resources:- Organizations (
id): your organization and the customer organizations you create withPOST /organization. A personal organization completes KYC; a business completes KYB. - Members (
memberId): the people who belong to a business organization, each named by thesubin their JWT. See Add organization member. - Payment accounts (
id): bank accounts and wallets, registered withPOST /organization/{organizationId}/payment_account. - Quotes (
quoteId): a priced transfer between two payment accounts. Valid for 2 minutes. - Orders (
id, equal to thequoteId): a transfer in progress. - Webhook subscriptions: the URLs we send events to.
Migrating from v1
The V1 → V2 guide lists endpoint replacements, request field changes, order statuses and webhook changes.Troubleshooting
See Errors for every problem type and what to do about it, and Authentication for401 issues.