Skip to main content
A quote is Endl’s priced answer to “if I send this, what arrives?”. It fixes an FX rate and a fee breakdown, stamps an expiry on them, and hands you an id. That id is the only way to start a transfer — nothing moves money without one.
A quote is time-boxed and single-use. It is good for ten minutes, and it can back exactly one transaction, ever.
This is the conceptual guide. For the endpoints themselves — parameters, schemas and worked bodies — see Generate quote and Get quote.

Where a quote sits

1

Price it

Generate quote. You get a qut_… id, the destination amount, the rate and every fee line.
2

Commit to it

Create pre-transaction takes the qut_ id and a recipient, and turns the price into an intent.
3

Send it

Submit transaction releases the money.
Everything on this page is about step one. The clock starts the moment the quote is generated, and it runs through steps two and three.

The four shapes

What a quote is follows entirely from the two currencies. Endl treats USDC, USDT and RLUSD as stablecoins and everything else as fiat.
The shape decides which KYC the customer needs, and the two are not interchangeable. A stablecoin-to-stablecoin transfer never touches a fiat account, so it needs only Sumsub verification. Anything that touches fiat through Bridge needs the full Bridge check. The one exception is Paywho-routed quotes, which also need only Sumsub.A customer who can quote USDC → USDC may therefore be refused on USDC → EUR. That is the gate working, not a bug.

What every quote must carry

Five things are mandatory on every request, whatever the shape. Plus exactly one amount, on one leg or the other.
depositRail is not free. A USDC or USDT source must use CRYPTO; any other source currency must not.Get it wrong and the message you receive names CRYPTO_WALLET or CRYPTO_MANUAL_WALLET — rails that do not exist in the v0 vocabulary. The message is stale; the value the validator actually wants is CRYPTO. Ignore the wording and send CRYPTO.
RLUSD is a special case on the source leg. It counts as a stablecoin when the shape is classified, and an RLUSD source is rewritten internally to USDC on arbitrum for routing, with an RLUSD conversion fee applied to the result. The deposit-rail rule above, though, only names USDC and USDT. Confirm RLUSD-as-source with Endl before building on it; RLUSD as a destination is unambiguous.

Forward and reverse quotes

Send source.amount to price forwards — “I am sending 1,000, what lands?”. Send destination.amount to price backwards — “the recipient must receive exactly 50,000, what do I send?”. Send one, never both, never neither. A reverse quote derives the source amount by working backwards through fees and FX, so the number you get back is not the simple inverse of the forward rate.

Rounding

Amounts are normalised to two decimal places before anything is priced (half-up), and rounded again on the way out — deliberately in your favour, never Endl’s:
  • source.amount is rounded up, because it is money coming in.
  • destination.amount is rounded down, because it is money going out.
So a reverse quote for exactly 50,000 can return a source amount a cent above the true figure. Do not assert exact equality when reconciling; compare to the cent.

Chains, and why they are spelled differently here

Whenever a leg is a stablecoin, the chain matters. On a one-sided shape the chain on the crypto leg is required; on stablecoin → stablecoin it is optional per leg, but validated whenever supplied.
Quotes use a different chain vocabulary from wallets. A wallet lives on ArbitrumOne; a quote names that network arbitrum. They are not interchangeable, and passing a wallet’s network name to a quote is one of the most common first-integration failures.
Quote chains are matched case-insensitively, so Base and base both work here. There is no quote chain for AvalancheC.
Testnet chain names are accepted only where the platform runs on testnets. In sandbox and QA you may name basesepolia, ethereumsepolia, arbitrumsepolia, optimismsepolia, polygonamoy, tronnile or xrpledgertestnet, and each is judged as the mainnet it mirrors. Production rejects all of them.

Not every currency is on every chain

Two rules, applied to each leg independently:
  • USDT is only issued on ethereum and tron. USDT on Base prices nowhere.
  • TRON carries only USDT. USDC on tron is refused.
A violation is 400 USDT is not supported on the base network (source.chain) — the message names the leg, so you know which half to fix.

Amount limits

Four separate ceilings can reject the same amount. They are checked in this order, and the first one to fire is the one you are told about — the order is deliberate, so you get the limit you can actually act on rather than an internal one.
1

Account-type limits

On a reverse quote whose derived source amount lands under the floor, a business is allowed down to 50 USD; an individual is not.
2

SWIFT's own floor

Any quote with SWIFT on either leg has a minimum of 15,200 USD, checked before the account-type floor.
3

Structural ceilings

The quote record itself cannot hold a source amount above 999,999.9999 or a destination amount above 99,999,999.99. These are not commercial limits and nothing is exempt from them.
4

The payout rail's published maximum

Each rail carries its own cap — the same number Get recipient required fields reports. Where several providers serve the same rail, the widest cap applies, so only an amount no provider could serve is rejected here.
Two routes sit outside the account-type band:
  • Stablecoin → stablecoin lifts the minimum but keeps the maximum. The 100 USD floor is a fiat-settlement rule and a crypto transfer can legitimately be smaller; the account ceiling still applies.
  • AED is priced from its own fee configuration rather than the shared USD band, on either leg.

Routing you do not control

You choose rails; you do not choose providers. Endl picks the provider from the currencies and the rail, and the choice is invisible in the response — but it changes which KYC the customer needs. A quote routes to Paywho when either leg is a Paywho-supported currency on a Paywho payout rail, or when either leg is INR on BANK_TRANSFER, IMPS, UPI or CRYPTO. Everything else routes to Bridge. Paywho-routed and stablecoin-to-stablecoin quotes need Sumsub verification; Bridge-routed quotes need the full Bridge check.

Pairs that are refused outright

SWIFT additionally has to be enabled on the customer. Being a business is necessary, not sufficient.

Reading the quote back

fxRate is not the rate you are charged at. It is the raw partner rate before markup; the markup is charged as a fee line instead. Reconciling by multiplying the source amount by fxRate will not reproduce destination.amount. Use the amounts, and use feeList for the breakdown.
Fee lines carry a feeCategoryTypeEnum — EXCHANGE_FEE, EXCHANGE_MARKUP_FEE, OUTGOING_PROCESSING_FEE, GAS_FEE, PLATFORM_FEE, PARTNER_FEE, TDS_FEE and others. Treat the set as open: display what you get, and do not switch exhaustively on it.
source.amountToConvert and amountToConvertActual are display-only fields describing what will actually be converted. Do not use them as inputs to anything.

Fields that are quietly ignored

Three things you might send have no effect, and none of them is an error:
  • partnerId — overwritten with whoever the API key authenticated as. You cannot file a quote under another partner.
  • overrideGasFee — a merchant-portal feature, dropped on the v0 surface. You get the quote you asked for, priced with Endl’s own gas fee.
  • Any unknown property — ignored rather than rejected.
That last one has teeth. Misspelling a field name produces a “missing field” error, not an “unknown field” one. If destination.currency is required and you sent destination.curency, what you will read is destination.currency field is required. Check your spelling before you check your logic.

The ten minutes

expiresOn is set 600 seconds after generation, and expiry is enforced when you use the quote, not when you read it. Get quote reports expired as a boolean and will happily return an expired quote — it is a record, not a reservation. Create pre-transaction is where an expired quote is refused.
A quote backs exactly one transaction. Once a transaction exists against a qut_ id, reusing it is refused with “Transaction already exists … get a fresh quote” — including after a failed or cancelled transaction.Retrying a failed submit means generating a new quote, not resending the old one. Build that into your retry path from the start.
Do not generate quotes speculatively to warm a cache. Price when the customer is ready to confirm, and re-price if they hesitate past the window.

Error handling

Quote failures are 400 with the specific reason in errors[0], and the messages are written to be shown to a user. The one quote-domain code is ERRQUO_1000 (404), for a quote that does not exist or belongs to another customer — the same answer either way, so quote ids cannot be probed. Everything else uses the shared envelope and the ERRCORE_ codes in Errors and the response envelope. Branch on errors[0].code, not on the message text.

Common pitfalls

The message is stale. Send depositRail: "CRYPTO". Those two rail names do not exist in the v0 vocabulary.
Quotes and wallets use different chain vocabularies. A wallet on ArbitrumOne is arbitrum to a quote; XrpLedger is xrp. See the mapping table above.
Unknown properties are ignored rather than rejected, so a misspelled field name reads as a missing one. Check the spelling of the field you think you sent.
Expected. fxRate is the pre-markup partner rate; the markup is a fee line, not a rate adjustment. Reconcile with the amounts and feeList.
Quotes are single-use, and the first attempt consumed this one — even if it failed. Generate a fresh quote for every attempt.
Get quote returns the record and reports expired: true. Expiry is enforced at Create pre-transaction, not on read.
Different KYC depth. Stablecoin-to-stablecoin needs only Sumsub; a fiat leg through Bridge needs the full Bridge check.
SWIFT is business-only. Both the customer record and the accountType in the body must say BUSINESS; having the rail enabled does not make an individual eligible. It also has a 15,200 USD floor.
Check both legs are stablecoins. The floor is lifted only for stablecoin → stablecoin; a stablecoin → fiat transfer keeps it.
The source amount wins silently. Send exactly one, so the quote prices the direction you meant.

Glossary

Written against Api-Version: 2026-09.1. Rail availability, per-rail caps and currency support are configuration and vary by customer and country — read them from List rails and Get recipient required fields rather than hardcoding this page.