Both rails require the same two things before you can even create the receiving account: the rail has
to be enabled for your partner (otherwise
403 INTERNATIONAL_NOT_ENABLED), and the business has to
have completed international onboarding (otherwise 409 ENTITY_ONBOARDING_INCOMPLETE, listing what
is outstanding). See International onboarding.
All calls below are against https://api.melio.com/v2, with your api-key header and a
Melio-Entity-Id header naming the business (ent_<uuid>, or me if you have a single entity).
1. Create the receiving account
international-fx
An FX account is described by its currency, its destination country and the bank identifiers that corridor uses. The shapes differ per corridor — an IBAN for EUR, a sort code for GBP, an IFSC code for INR, a CLABE for MXN, and so on — soPOST /accounts accepts twelve variants
of CreateExternalInternationalFxAccountRequest. The full currency → destination → bankDetails
table lives in the OpenAPI description of that schema; each currency also has a ready-to-send request
example on POST /accounts, which is the fastest way to get the identifiers right.
USDis not accepted on this type. A dollar payment converts nothing, so there is no FX rail to put it on — use a domestic account type, orinternational-gusd. AcurrencyofUSDhere is rejected with400 VALIDATION_ERROR.- A currency outside the documented table is
400 UNSUPPORTED_CURRENCY. Even a listed currency can be refused for a given destination: the international-payments service is the authority on what it can deliver today.
international-gusd
A GUSD account is just a wallet:2. Check the business can pay internationally
GET /limitations reports payment.domestic:write and payment.international:write independently.
A business may be able to pay domestically and be blocked internationally, or the reverse, so check
the international one rather than assuming:
reasons[].code is worth branching on: MissingInformation is something you can fix (see
onboarding), while LocationRestricted is not — the FX provider
will not onboard a business registered in Nevada, the US Virgin Islands, Guam or the Northern
Mariana Islands, and its reason carries an empty missingFields because there is no data that would
lift it. Creating a payment for a blocked business returns 403 BUSINESS_NOT_ELIGIBLE.
3. Create the payment
The request body differs by rail, anddeliveryPreference decides which one you are sending.
POST /payments also requires an Idempotency-Key header (a UUID is fine) so the call is safe to
retry — omitting it is 400 IDEMPOTENCY_KEY_REQUIRED, and reusing one with a changed body is
409 IDEMPOTENCY_KEY_REUSED.
international-fx
amountis what the counterparty receives, in minor units ofcurrency— 100000 is €1,000.00. The business is debited the equivalent in USD at the applied rate, plus fees.currencymust equal the receiving account’s currency. A mismatch is400 VALIDATION_ERROR.fxQuoteTokenis optional. With it you are charged exactly what was quoted; without it the payment is priced at creation. See FX quotes and rates.compliance.purposeis required, and a few corridors want a code rather than prose (below).- Some destinations additionally require a supporting document — see Payment attachments.
international-gusd
currency defaults to USD and
can be omitted, and there is nothing to quote and no purpose to declare. Sending fxQuoteToken or
compliance.purpose on this rail is rejected with 400 VALIDATION_ERROR rather than accepted and
ignored — a purpose that never reaches a provider should not look like one that did.
Payment purpose
compliance.purpose is what the currency provider is told about why the money is moving. It is
usually free text, but three corridors take a code from a fixed set and refuse anything else:
Send free text to one of those and the request is rejected with
400 VALIDATION_ERROR listing the
values it accepts, so you can surface them without hard-coding the list. The provider owns these
sets: treat the table as examples and read the error for the current set.
Delivery speed
international-fx is the rail’s normal speed. fast-international-fx is the expedited variant and
is subject to a per-payment eligibility check — an ineligible request is rejected with 400, never
silently downgraded. POST /tools/fast-payment-eligibility answers for the prospective payment
before you create it, and returns a decision per fast preference valid for the accounts involved,
fast-international-fx among them. GUSD has a single speed.
Pricing and timing
Both rails are supported by the two estimate endpoints, and both are independent of the FX quote:POST /tools/fee-calculator— the fees for a given amount, originating account and preference.POST /tools/delivery-eta— the expected delivery date.
Errors worth handling
See also
- International onboarding — what the business and its owners must provide first
- FX quotes and rates — locking a rate versus taking the market rate
- Payment attachments — uploading documents and when they are required