Send a payout link
Create a single-use link on your server, send its URL to the recipient, and the payout goes out once they enter their own bank details on the page Avvio hosts. Payout links explains when to use one.
- Create the link with
POST /payments/organizations/{orgId}/payout-links. - Send its
url. The hosted page callsGET /payout-links/{token}andPOST /payout-links/{token}/submitfor you. - Check the outcome from the
payout.*webhooks orGET .../orders.
-
Create a payout link
Section titled “Create a payout link”Call
POST /payments/organizations/{orgId}/payout-linksfrom your backend.To try it from the API reference, authorize with an
avvio_test_*key (never a live one), enter your normalorgId, set a newIdempotency-Key, fill in the body and click Try It. Open the response’surlto play the recipient.POST /payments/organizations/{orgId}/payout-linksx-api-key: avvio_live_…Idempotency-Key: 3f81e921-bc01-447a-9a11-0982716a5b42Content-Type: application/json{"amount": "75.00","destinationCurrency": "MXN","endUserId": "customer_42","reference": "ZZ-WAGE-1","expiresInMinutes": 60}amountis a USD decimal string with at most two fractional digits.destinationCurrencyis a three-letter ISO 4217 code for a currency your organization can pay out to. For USD, the hosted form asks for the fields of the USD corridor your organization is served: a domestic US account or an international bank’s SWIFT details, depending on its routing (readGET /recipients/{orgId}/corridors).endUserIdis required, 1–128 characters.referenceis optional, 1–128 characters of letters, digits, spaces and. _ : -.expiresInMinutesis a whole number from 1 to 10,080; it defaults to 60. Any other top-level field is refused with400 VALIDATION_ERROR.The link’s
amountis what the recipient receives, in USD value: the fee is added on top, so your balance is debitedamountplus the fee.endUser.nameandendUser.emaildescribe your end user, the person sending the money, not the account holder being paid. SendendUser.emailwhen you have it. The regulatory receipt is emailed to the sender, and a link created without an address makes the hosted page ask for one before it will pay.Response:
{"payoutLinkId": "cmf3k2xh10010q8b7a3c5e7gj","url": "https://pay.avvio.xyz/l/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...","expiresAt": "2026-08-17T05:28:39.569Z","status": "pending"}Your
Idempotency-Keyis stored on the link record. Creating the link twice, or a recipient submitting several times, cannot produce two payouts. -
Send the URL, and let the page do the rest
Section titled “Send the URL, and let the page do the rest”Send
urlto the recipient by SMS, email or your app. The hosted page then calls two public endpoints with the single-use signed token from the URL:GET /payout-links/{token}POST /payout-links/{token}/submitSend no
x-api-keyorIdempotency-Keyto these routes. The short-lived token in the path is the credential. It is a signed JWT: it cannot be forged, but its payload (the link id and your organization id) is readable by anyone who has the URL. Don’t decode, construct or log it.The read returns what the page renders:
sender.name, your organization’s display name, so the recipient recognizes the payment. The response body carries no organization id.- The amount and the fields the corridor needs.
- The end user’s saved accounts, masked to name and last 4.
- A
previewof the rate, the fee and roughly what lands. paymentReasonsanddefaultPaymentReasonfor corridors that need a purpose, and the Regulation Edisclosure.
The preview has the same shape as
GET /ratesand is indicative for the same reason: the binding quote is priced at submit, against the bank details the page collects. Because the link pays exact output,destinationAmountisamount×rateandtotalDebitisamount+fee. When the corridor can’t be priced in advance,previewis omitted and the link is still payable.{"sender": { "name": "Northstar Logistics" },"amount": { "currency": "USD", "amount": "75.00" },"destinationCurrency": "MXN","reference": "ZZ-WAGE-1","expiresAt": "2026-08-17T05:28:39.569Z","status": "pending","requirements": [ { "id": "clabeNumber", "title": "CLABE", "pattern": "^[0-9]{18}$", "required": true } ],"savedDestinations": [ { "destinationAccountId": "sbx_acct_MXN_4471_ae66cbc5", "name": "Ana Ruiz", "label": "BBVA México", "last4": "4471" } ],"preview": {"indicative": true,"sourceAmount": { "currency": "USD", "amount": "75.00" },"destinationAmount": { "currency": "MXN", "amount": "1275.75" },"fee": { "currency": "USD", "amount": "0.38" },"totalDebit": { "currency": "USD", "amount": "75.38" },"rate": "17.010050924685068"}}Submit exactly one of these bodies:
{ "esignConsent": true, "name": "María González", "email": "[email protected]", "details": { "clabeNumber": "012180000080004471" } }{ "esignConsent": true, "destinationAccountId": "sbx_acct_MXN_4471_ae66cbc5" }For a new destination,
namemust be non-empty,emailvalid, anddetailskeyed by the field ids from the read. Don’t mix a saveddestinationAccountIdwith new-destination fields.esignConsentis required on both and must betrue. The page shows it as an unticked checkbox: the sender’s consent to receive their receipt electronically under the E-Sign Act. A submit without it is400 VALIDATION_ERROR, and the link stays spendable.Either body may also carry
senderEmail, the sender’s own address, for links created withoutendUserEmail. With neither, the submit is refused with400 VALIDATION_ERROR(senderEmail: required) before anything is registered or paid, because the receipt could not be delivered.The receipt
Section titled “The receipt”A link payout is a remittance transfer under Regulation E, so the sender is emailed a receipt on submit, and the submit response returns the same figures as
disclosurefor the page to show. Payout links lists what the receipt contains.Token handling
Section titled “Token handling”- The body of
GET /payout-links/{token}never carries yourorgId, yourendUserIdor full bank details. The token itself carries the organization id, as above. - A second submit returns the original payout with
status: "already_submitted", so a double tap on a flaky mobile connection pays once. - A validation error, such as mistyped account digits, keeps the token active so the recipient can correct it. A payment-network error after the link has been claimed marks it
failedfor good; mint a new link. - Reading an expired or tampered token returns the same
404 Not Foundin every case. A link that is being paid or has failed still reads, with thatstatus.
-
Check the outcome
Section titled “Check the outcome”A submitted link becomes an ordinary payout, debited from your balance when it is accepted. On a routing where you fund each payout yourself, it waits with
requiresFunding: trueuntil you do (Fund your balance). Follow it with thepayout.*webhooks orGET /payments/organizations/{orgId}/orders/{payoutId}, as in Track status & failures. Link payouts count against the same caps as any other payout (Send a payout).
Was this page helpful?