Get a payout link
Returns what the recipient's page renders.
Path parameters
tokenstringRequiredOpaque signed bearer token from the link URL. It is JWT-shaped but its claims are not a public contract; do not decode, construct, log, or store it beyond the recipient session.
Behavior
Takes no credential. The signed token in the URL is the credential, which is why it is short-lived and single-use.
Returns the amount, the fields that corridor needs, and saved
destinations masked to name, label, and last four digits. It returns no
organization id, no endUserId, and never full bank details.
A public route that echoes back what was typed turns a forwarded link
into a disclosure of someone's account number.
Expired, spent, forged and tampered tokens are all a flat 404. A
stranger probing links learns nothing from the difference.
Responses
200What to render.
Body
senderobjectOptionalWho is paying: your organization's display name, so the recipient can recognize the payment. The name only; the organization id is never exposed here.
Show 1 property
namestringRequired
amountobjectRequiredAlways a decimal string, never a float and never base units. Floats lose cents at scale; base units mean every integrator re-derives the exponent.
Show 2 properties
currencystringRequiredamountstringRequired
destinationCurrencystringRequiredreferencestringOptionalexpiresAtstring<date-time>RequiredstatusstringRequiredconsumedandexpiredlinks return 404 and are never exposed here.Allowed values:pendingconsumingfailedrequirementsarray of objectRequiredShow 6 properties
idstringRequiredtitlestringOptionaltypestringOptionaldescriptionstringOptionalpatternstringOptionalrequiredbooleanOptional
savedDestinationsarray of objectRequiredMasked destinations scoped to this link's end user and currency.
Show 4 properties
destinationAccountIdstringRequirednamestringRequiredlabelstringOptionallast4stringOptional
paymentReasonsarray of objectOptionalThe corridor's payment purposes, for the page's picker; send one
idaspaymentReasonon submit. Omitted when the corridor asks for none.Show 2 properties
idstringRequiredlabelstringRequired
defaultPaymentReasonstringOptionalThe purpose used when none is chosen. Present only with
paymentReasons, and only when the corridor names one.previewobjectOptionalWhat the page shows above the form: the rate, the fee, and roughly what lands in the recipient's account. The same shape as
GET /rates, and indicative for the same reason: the binding quote is priced at submit, against the bank details this page collects. Omitted when the corridor cannot be priced in advance; the page still renders and the link is still payable.More
A link converts its whole amount and adds the fee on top, unlike
GET /rates:destinationAmount = amount x rate, andtotalDebit = amount + fee(not equal tosourceAmounthere).Show 7 properties
indicativebooleanOptionalAlways true here. This is an estimate, not a locked rate.
sourceAmountobjectOptionalAlways a decimal string, never a float and never base units. Floats lose cents at scale; base units mean every integrator re-derives the exponent.
Show 2 properties
currencystringRequiredamountstringRequired
destinationAmountobjectOptionalAlways a decimal string, never a float and never base units. Floats lose cents at scale; base units mean every integrator re-derives the exponent.
Show 2 properties
currencystringRequiredamountstringRequired
feeobjectOptionalCharged on the send side and deducted before conversion.
Show 2 properties
currencystringRequiredamountstringRequired
totalDebitobjectOptionalWhat leaves your balance. On
GET /ratesthe fee is deducted from the send rather than added on top, so this equalssourceAmount. A payout link's preview adds the fee on top, so there it issourceAmount + fee. Read this field rather than assuming either.Show 2 properties
currencystringRequiredamountstringRequired
ratestringOptionalThe indicative mid-rate, before the fee: destination units per source unit converted, "1 USD = 17.01 MXN".
destinationAmount = (sourceAmount - fee) x rate. This is a different number fromPayout.rate, which is the effective rate with the fee inside (destination over source), so it reads lower by the fee share for the same conversion. The rate did not move.limitsobjectOptionalThe corridor's floor and ceiling, in the source currency.
Show 2 properties
minstringOptionalmaxstringOptional
disclosureobjectOptionalThe US Regulation E remittance disclosure, as the hosted page renders it:
prepaymenton the resolve (estimated, omitted when the corridor cannot be priced),receipton the submit. Renderlinesin order.Show 4 properties
kindstringRequiredAllowed values:prepaymentreceiptestimatedbooleanRequiredlinesarray of objectRequiredShow 3 properties
labelstringRequiredvaluestringRequiredsignstringOptionalAllowed values:+-
otherFeesDisclaimerstringRequired
Errors
404Not valid (expired, already spent, or never existed).
429Too many requests. The default ceiling is 100 requests per minute per API credential on a 60-second window. High-volume payout and reconciliation routes declare a 600/minute override, and batch submission a 30/minute ceiling. A separate 2,000/minute per-source-IP abuse ceiling always applies.
Obey
Retry-After; it is in seconds and is authoritative. A 429 means the request was refused before the handler ran. Retry reads normally; retry an idempotent mutation with its sameIdempotency-Key.
Error body · Error
typestringRequiredStable machine-readable code.
detailstringRequiredWhat went wrong, in a sentence. Always a string, so
detail.toLowerCase()is safe.More
This is the field to read on
BAD_REQUESTandPROVIDER_REJECTED, where the type alone does not name the condition.messagestringRequiredThe same text as
detail, kept for integrations written beforedetailexisted. Readdetail.resolutionstringOptionalWhat to do about it, when there is a specific answer. It is not on every error (it is absent on
BAD_REQUEST,NOT_FOUND,PAYOUT_NOT_CANCELABLEandDESTINATION_ACCOUNT_NOT_FOUND), so treat it as optional and fall back todetail.statusintegerRequiredHTTP status, repeated in the body.
statusCodeintegerRequiredThe same value as
status, kept for integrations written beforestatusexisted. Readstatus.requestIdstringRequiredQuote this to support and we can find the exact request. Also sent as the
x-request-idresponse header, which is the only place it appears on a successful response. Success bodies do not carry it. Send your ownx-request-idon the request and we use it, so your trace and ours share one identifier; otherwise we mint one.errorsarray of stringOptionalPresent on VALIDATION_ERROR; names each field that failed.
originalIdempotencyKeystringOptionalOn
DUPLICATE_REQUEST_DETECTEDonly. Send the request again with this to receive the original payout instead of making a second one. Without it there is no way to recover except by risking a double payment.originalPayoutIdstringOptionalOn
DUPLICATE_REQUEST_DETECTEDonly. The payout the first request created.originalBatchIdstringOptionalOn a batch
DUPLICATE_REQUEST_DETECTED. The run the first request created.originalRequestIdstringOptionalOn a
409 PAYOUT_OUTCOME_UNKNOWNreplay. TherequestIdof the call whose outcome is unknown; quote it to support.existingRecipientIdstringOptionalOn
BANK_ACCOUNT_ALREADY_LINKED. The recipient in your organization that already holds this account.existingMethodIdstringOptionalOn
BANK_ACCOUNT_ALREADY_LINKED. The payment method on that recipient.
Branch on type, never on the status or the message. Every error type is listed with what to do about it.
Was this page helpful?