Payout Beneficiary
Resolve who owns a PIX key and lock the price of the payout to it, then pay against the quoteId.
Overview
POST /api/wallet/payout/beneficiary answers the two questions
/api/wallet/payout cannot answer before it is too late: who the
PIX key belongs to, and what the payout will cost. It returns the payee's name, masked
tax id and bank, the full price, and a quoteId you pass to the payout — which then settles
exactly what was quoted.
Nothing is debited here. No transaction is created, no PIX is paid, and calling it twice costs nothing but a second quote.
A quote is a lock, not an estimate.
/api/wallet/payoutreads the fee, the FX rate, the asset and the destination from the quote instead of pricing them again. This is what makes it different fromPOST /api/quote, which is indicative pricing for any pair and reserves nothing.
Only a PIX key is quotable. A BR Code already carries its own amount and payee — pay it
directly with qrCode on /api/wallet/payout.
Flow
POST /api/wallet/payout/beneficiary— show the user the name that came back, and the fee.POST /api/wallet/payoutwithquoteId+walletPin— settles at the quoted price.GET /api/wallet/payout/{transactionId}— poll untilCOMPLETEDorFAILED.
The quote expires 5 minutes after it is issued, and is consumed by the payout that uses
it. An expired, unknown or already used quoteId answers 400 — quote again.
Request
curl --request POST \
--url https://api.hodle.com.br/api/wallet/payout/beneficiary \
--header "Authorization: Bearer $API_KEY" \
--header "Content-Type: application/json" \
--data '{
"value": 5000,
"network": "base",
"asset": "BRLA",
"pixKey": "[email protected]",
"pixKeyType": "EMAIL"
}'const res = await fetch('https://api.hodle.com.br/api/wallet/payout/beneficiary', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.HODLE_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
value: 5000,
network: 'base',
asset: 'BRLA',
pixKey: '[email protected]',
pixKeyType: 'EMAIL',
}),
})
const quote = await res.json()import os, requests
res = requests.post(
"https://api.hodle.com.br/api/wallet/payout/beneficiary",
headers={
"Authorization": f"Bearer {os.environ['HODLE_API_KEY']}",
"Content-Type": "application/json",
},
json={
"value": 5000,
"network": "base",
"asset": "BRLA",
"pixKey": "[email protected]",
"pixKeyType": "EMAIL",
},
)
quote = res.json()Parameters
| Field | Type | Required | Description |
|---|---|---|---|
value | integer | Yes | Amount the beneficiary receives, in BRL cents. Min 10. The fee is charged on top of it. |
network | string | Yes | polygon, base, tron or solana. |
asset | string | No | Stablecoin to debit. Defaults to the network default. A quote does not fall back to a second asset the way the payout does — it names the one it priced. |
pixKey | string | Yes | PIX key of the beneficiary. |
pixKeyType | string | Yes | PHONE, CPF, EMAIL, RANDOM or CNPJ. |
taxId | string | No | Beneficiary CPF/CNPJ. Needed when paying a third party — see Third-party operations. |
subAccountId | string | No | The subaccount the payout is for. Recorded on the quote; /api/wallet/payout has to be called with the same one. |
Response
{
"success": true,
"status": "PENDING",
"quoteId": "b0f1c7de-9f2b-4a71-9c1e-2f4e2a1d6c88",
"expiresAt": "2026-08-31T14:35:00.000Z",
"settlement": "OWN_ACCOUNT",
"network": "base",
"asset": "BRLA",
"pixKey": "[email protected]",
"pixKeyOwner": {
"name": "Thiago Mota dos Santos",
"taxId": "545.***.***-10",
"bankName": "NU PAGAMENTOS - IP"
},
"quote": {
"inputAmount": 50.75,
"inputCurrency": "BRLA",
"outputAmount": 50,
"outputCurrency": "BRL",
"rate": 1,
"fee": 0.75
},
"payoutId": "6a878236a83b0a4e8cc8c40b",
"correlationId": "b0f1c7de-9f2b-4a71-9c1e-2f4e2a1d6c88"
}| Field | Description |
|---|---|
status | PENDING — the payout is already reserved at the settling account and is waiting to be paid. QUOTED — a price, with nothing reserved behind it. See Reserved payouts. |
quoteId | Pass as quoteId on /api/wallet/payout. |
expiresAt | When the locked price stops being honoured (5 minutes). |
settlement | Which account settles the PIX: OWN_ACCOUNT (the account opened in your name) or HODLE. |
pixKeyOwner | Who the key belongs to, as the provider reports it. taxId is masked at the source — show it to the user, do not try to match it. |
payoutId | Id of the reserved payout at the settling account. Only when status is PENDING. |
correlationId | Idempotency key of that reserved payout. Only when status is PENDING. |
Reading the quote
| Field | Meaning |
|---|---|
inputAmount | Stablecoin debited from the wallet: value + fee, converted at rate. |
outputAmount | BRL the beneficiary receives — exactly value. |
rate | BRL per unit of inputCurrency. 1 for the BRL-pegged assets (BRLA, BRS). |
fee | Hodle's fee, in BRL. Already includes any affiliate discount your account carries. |
Paying against the quote
Send the quoteId with the wallet credentials. pixKey and pixKeyType may be omitted —
they come from the quote:
curl --request POST \
--url https://api.hodle.com.br/api/wallet/payout \
--header "Authorization: Bearer $API_KEY" \
--header "Content-Type: application/json" \
--data '{
"value": 5000,
"network": "base",
"quoteId": "b0f1c7de-9f2b-4a71-9c1e-2f4e2a1d6c88",
"walletPin": "1234",
"protectedSymmetricKey": "AoofiKHyVRLvdrknnXzo..."
}'What the payout takes from the quote: the fee, the FX rate, the asset, the destination, and
— when the payout was already reserved — the reservation it releases. What you send is
only checked against it: value, network, asset, pixKey and subAccountId must agree
with the quote or the request is refused with, for example,
"value does not match the quote".
quoteIdneedswalletPin. A quoted payout is signed by Hodle. The sign-on-your-own-device legs (payoutIntentId+signature) carry their own quote and do not take aquoteId.
Reserved payouts (status: PENDING)
When the PIX is settled by an account opened in your name (settlement: "OWN_ACCOUNT"), the
quote does more than price the payout: it reserves it, and /api/wallet/payout then only
releases the reservation. That is what status: "PENDING" means, and it is why payoutId
comes back — the payout already exists, waiting to be paid. One round trip less at the moment
the money moves, and no way for the payout to come out at a different price than the one you
were quoted.
A reservation needs the settling account to already hold the balance, which an account that
keeps no float does not: the stablecoin only arrives with the debit, at settlement time. The
quote then answers status: "QUOTED" instead — a price, with nothing reserved behind it. The
quoteId works exactly the same way; the payout is simply created when it is paid, as it
always has been.
A reserved payout that is never paid stays
PENDING. There is no cancel route for it. Quote when the user is about to pay, not speculatively.
Errors
| Status | When |
|---|---|
400 | Validation failure, or a PIX key the DICT does not resolve. |
401 | Missing or invalid API key. |
403 | Account blocked, API payouts not enabled (ask support), over a limit, blocked PIX key, or a third-party payout not enabled. |
429 | Quote cooldown for this account. |
502 | The FX rate could not be read, or an account settling on its own account could not establish its settling account because the provider limit is unavailable. No payout or quote is created; retry the beneficiary request later. |
503 | PIX payments are temporarily disabled, or the quote could not be stored. |
Requires API payouts enabled on the account, like
/api/wallet/payout — ask support.
Wallet Payout
Pay PIX from a user's USDT, USDC, BRLA or BRS balance on Polygon, Base, Tron or Solana in a single API call.
Payout from Your Own Wallet
Pay a PIX from BRS held in a Solana wallet you control, such as a Privy embedded wallet. Hodle prepares the debit, your user signs it, Hodle pays the PIX.