Skip to main content
POST
Generate quote

Stablecoin → stablecoin

A USDC / USDT / RLUSD quote on both legs. Six fields are mandatory, and all of them are rejected at the door before any pricing happens:
depositRail must be CRYPTO for a stablecoin source, and payoutRail must be CRYPTO for a stablecoin destination — SWIFT is rejected outright for a crypto destination.

Chain support

chain is optional on this route, but a pair you do send is validated against what Endl actually issues. Chain codes are matched case-insensitively.
Tron carries USDT only. Any non-USDT currency on tron is rejected.

Amount limits

Stablecoin → stablecoin lifts the 100 USD minimum but keeps the maximum. The floor is a fiat-settlement rule and a crypto transfer can legitimately be smaller; the per-account-type ceiling still applies on this route exactly as it does elsewhere. Two structural ceilings also apply, because the quote row has to store the numbers. Nothing is exempt from these: On every other route the floor applies too — 100 USD for both account types, and 15,200 USD if SWIFT is on either leg, checked first. Each payout rail also carries its own published maximum; where several providers serve one rail the widest cap applies. A reverse quote is bounded by the same range. The source amount is not known when the request is validated, so the limits are enforced against the derived amount once pricing has run — which is why a reverse quote can be rejected for a source amount you never sent. A business is allowed down to 50 USD there; an individual is not.

KYC depth

A stablecoin → stablecoin quote has no fiat leg, so the end user needs Sumsub KYC only. Bridge KYC applies to Bridge-routed fiat quotes; Paywho-routed ones take the Sumsub gate too.

Authentication

X-API-KEY is not read. Header names are case-insensitive, so API-KEY and api-key are the same header — but X-API-KEY is a different name and is ignored. If you have an integration predating the header rename, that is the first thing to check.
There is no secret header; the key alone authenticates, and it must carry the quotes permission.

Error messages on this route

Branch on errors[0].code, never on the message. The top-level message is "GetQuote failed!" on every rejection below — it is not the reason. The reason is errors[0].message, and the code is errors[0].code. Every quote code is documented on Error codes.
One message names rails that no longer exist: For USDC/USDT source currency, depositType must be CRYPTO_WALLET or CRYPTO_MANUAL_WALLET. It fires when depositRail is not CRYPTO for a stablecoin source — send CRYPTO; the names in the message are legacy and are not valid enum values.

Working request

Working response

200, and the body is the quote itself — there is no envelope around a success on this surface.
source.amount × fxRate will not equal destination.amount. fxRate is the raw partner rate before markup, and the markup is charged as a fee line rather than folded into the rate. Reconcile with the amounts and feeList.
Nulls are present, not omitted, and decimal scale is preserved exactly as computed — 0.9990, not 0.999. Parse the numbers as decimals; do not assume a fixed number of places, and never compare them as strings.
The quoteId that comes back is what you pass to Submit transaction, together with the recipientId.

Authorizations

API-KEY
string
header
required

Your partner API key.

Headers

Api-Version
string
default:2026-09.1
required

The API version this request targets. Required on every /api/v0/* call. Format YYYY-MM.<release>; 2026-09.1 is the latest. The version that served the request is echoed back on the response. Missing, malformed or unsupported values are rejected with 400.

Pattern: ^\d{4}-\d{2}\.\d+$

Path Parameters

userId
string
required

The customer the quote belongs to. Must be a cus_… reference id, and must belong to your partner account. Malformed, unknown, soft-deleted or another partner's → 404 ERRREF_1001.

Example:

"cus_9HqA2mT7xK4vRb1NdLpZ"

Body

application/json
depositRail
enum<string>
required

How the funds arrive. Coupled to source.currency — see the RAIL rule.

Available options:
CRYPTO,
ACH,
FEDWIRE,
SEPA,
SEPA_CT,
SWIFT,
IMPS,
UPI,
EFT,
FPS,
CHAPS,
PIX,
SPEI,
AED_LOCAL,
ENDL_ACCOUNT,
TOPUP_FIAT
payoutRail
enum<string>
required

How the funds leave. A superset of the deposit rails.

Available options:
CRYPTO,
ACH,
FEDWIRE,
SEPA,
SEPA_CT,
SWIFT,
IMPS,
UPI,
EFT,
FPS,
CHAPS,
PIX,
SPEI,
AED_LOCAL,
ENDL_ACCOUNT,
TOPUP_FIAT,
BANK_TRANSFER,
CASH_PICKUP,
ALIPAY,
CHINA_UNIONPAY_CARD_TRANSFERS,
HUMO_UZCARD,
ELCARD_TRANSFER,
KORTI_MILLI_TRANSFER,
BANK_CARD_TRANSFER
accountType
enum<string>
required

INDIVIDUAL or BUSINESS.

Available options:
INDIVIDUAL,
BUSINESS
source
object
required
destination
object
required

Response

The quote. Unwrapped — the body is the quote object itself, with no { data, code, message, status } envelope.

quoteId
string

The quote reference id — qut_…. Pass it to Create pre-transaction.

partnerId
string

The partner the key authenticated as, as a ptr_… reference id. Whatever you sent is overwritten.

depositRail
string

Echoed. payoutRail is not echoed — the response carries no payout rail at all.

source
object
destination
object
expiresOn
string

Ten minutes after generation. Expiry is enforced when the quote is used, on Create pre-transaction.

fxRate
number

The partner rate before markup. The markup is charged as a fee line, so source.amount × fxRate will not reproduce destination.amount.

feeList
object[]

One entry per fee line. feeCategoryTypeEnum is the one to switch on, and the set is open.

feeTotal
number

Sum of feeList.

feeTotalActual
number

The settled fee total.

feeCurrency
string

Always the source currency.

bonusAmount
number | null

null when none applies.

coupon
object | null

Only populated when a coupon applied. null otherwise.

gasFeeBreakdown
object | null

Estimated vs charged on-chain gas. null when the route has no on-chain leg. The charged amount is already in feeList.