Deposit Asset
Create a deposit via Lightning, USDT, USDC, USDCE, BRLA, or BRS.
POST /api/deposit/asset
Create a deposit that converts BRL to the specified crypto asset. For BRS, the asset is minted to the user's own Hodle Solana wallet; the other assets are sent to the provided address.
Request
curl --request POST \
--url https://api.hodle.com.br/api/deposit/asset \
--header "Authorization: Bearer $API_KEY" \
--header "Content-Type: application/json" \
--data '{
"value": 5000,
"address": "lnbc500u1pj...",
"asset": "LIGHTNING",
"externalId": "my-order-123"
}'const res = await fetch('https://api.hodle.com.br/api/deposit/asset', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.HODLE_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
value: 5000,
address: 'lnbc500u1pj...',
asset: 'LIGHTNING',
externalId: 'my-order-123',
}),
})
const data = await res.json()import os, requests
res = requests.post(
"https://api.hodle.com.br/api/deposit/asset",
headers={
"Authorization": f"Bearer {os.environ['HODLE_API_KEY']}",
"Content-Type": "application/json",
},
json={
"value": 5000,
"address": "lnbc500u1pj...",
"asset": "LIGHTNING",
"externalId": "my-order-123",
},
)
data = res.json()Body example
{
"value": 5000,
"address": "lnbc500u1pj...",
"asset": "LIGHTNING",
"externalId": "my-order-123"
}Parameters
| Field | Type | Required | Description |
|---|---|---|---|
value | integer | Yes | Amount in BRL cents. Must be a positive integer. |
address | string | Cond. | Destination address. Required for LIGHTNING, USDT, USDC, USDCE, and BRLA; omit for BRS, which is minted to the account's own Hodle Solana wallet. |
asset | string | Yes | Asset type: LIGHTNING, USDT, USDC, USDCE, BRLA, BRS, DEPIX, or BTC. |
network | string | Cond. | On-chain network for the asset. Required for USDT, USDC, USDCE, and BRLA; BRS only supports solana and defaults to it when omitted. Not needed for LIGHTNING. See Assets & Networks. |
externalId | string | No | Your own ID for reconciliation. Must be unique per deposit (idempotency key). A UUID is generated if not provided. |
subAccountId | string | No | The subaccount this deposit belongs to (scoped to your API key — an id you do not own is refused with 404). Defaults to the main account. What it does depends on how your account is set up — see What subAccountId does. |
taxId | string | No | CPF/CNPJ of the payer, when the payer is not the account holder. Digits only or masked. Rejected with 403 when third-party operations are not enabled for the account. On its own it does not let a third party pay the charge — see Who can pay the PIX. |
What subAccountId does
What the field selects depends on how your integration is set up. There are two setups, and Hodle configures which one your account is on:
Your customers ramp through the partner. The deposit is settled on that subaccount's own account at the regulated partner, under their KYC. This is why an asset/network the partner does not cover is refused here rather than quietly falling back to your own rail — settling a customer's money on your balance is not the same operation.
Your customers are onboarded through Hodle's partner KYC, but your ramp settles elsewhere. Your subaccounts have no rail of their own to receive a deposit, so the field does not select one. The deposit runs on your own account — your rails, limits, fees and KYC, with every asset you normally support — and the id is recorded on the charge, so you can still tell which of your customers each deposit came from.
Ownership is checked either way: a subaccount id you do not own is refused with 404. The
same setup governs POST /api/wallet/payout. Ask support if you are
not sure which one your account is on.
Who can pay the PIX
The PIX charge returned by this endpoint can only be paid by the CPF/CNPJ that owns the
account the deposit belongs to — the subaccount holder when subAccountId selects the
rail, your own account otherwise. A PIX
sent by anyone else is refused by the bank at payment time and no crypto is delivered.
To accept a PIX paid by a third party — for example when you charge your own end customer
on your account — ask support to enable DEPOSIT_THIRD_PARTY on the account.
Assets & Networks
| Asset | Networks | Address format |
|---|---|---|
LIGHTNING | lightning | Lightning invoice or LNURL email |
USDT | polygon, arbitrum | EVM address (0x...) |
USDC | polygon, base, gnosis | EVM address (0x...) |
USDCE | gnosis | EVM address (0x...) |
BRLA | polygon, base | EVM address (0x...) |
BRS | solana | Own Hodle Solana wallet |
DEPIX | spark, liquid | Spark address (spark1...) or Liquid address |
BTC | spark | Spark address (spark1...) |
Available networks per asset can depend on your account configuration and KYC level. For the full matrix across every endpoint see Assets & Networks.
BRS requires the NORA_RAIL flag and is always minted to the user's own Hodle Solana
wallet. It does not accept a third-party destination. See BRS.
Address Formats
For LIGHTNING assets, the address can be:
- A Lightning invoice starting with
lnbc,lntb, orlnbcrt - An LNURL email in the format
user@domain.com
For USDT, USDC, USDCE, and BRLA assets, the address is an EVM address (0x...) on the selected network.
For BRS, omit address; the asset is minted to the account's own Hodle Solana wallet.
Response
{
"success": true,
"externalId": "my-order-123",
"qrCode": "lnbc500u1pj...",
"fee": 100,
"fxRateAtTx": 408000.50,
"walletCharge": "charge_abc123"
}Fields
| Field | Type | Description |
|---|---|---|
success | boolean | Whether the deposit was created. |
externalId | string | The external ID for reconciliation (your value or auto-generated UUID). |
qrCode | string | null | QR code for the deposit. |
fee | number | Fee charged for the deposit. |
fxRateAtTx | number | BTC/BRL exchange rate at the time of transaction. |
walletCharge | string | null | Wallet charge identifier. |
Errors
{
"success": false,
"error": "Validation failed",
"details": [
{ "field": "value", "message": "Expected number, received string" }
]
}{
"success": false,
"error": "A deposit with this externalId already exists"
}GET /api/deposit/asset/{externalId}
Reads a deposit back: whether the PIX was paid, whether the asset was delivered, and — on your own virtual account — who paid the QR code.
Poll it, or use it to reconcile after a
DEPOSIT_ASSET_SUCCESS webhook.
Request
curl --request GET \
--url https://api.hodle.com.br/api/deposit/asset/my-order-123 \
--header "Authorization: Bearer $API_KEY"const res = await fetch(
'https://api.hodle.com.br/api/deposit/asset/my-order-123',
{ headers: { Authorization: `Bearer ${process.env.HODLE_API_KEY}` } },
)
const data = await res.json()import os, requests
res = requests.get(
"https://api.hodle.com.br/api/deposit/asset/my-order-123",
headers={"Authorization": f"Bearer {os.environ['HODLE_API_KEY']}"},
)
data = res.json()Parameters
| Field | In | Required | Description |
|---|---|---|---|
externalId | path | Yes | The externalId of the deposit — your own value, or the UUID we generated and returned on the POST. |
subAccountId | query | Cond. | Required when the deposit was created with subAccountId. Send the same id back; an id you do not own is refused with 404. |
Response
{
"success": true,
"data": {
"externalId": "my-order-123",
"walletCharge": "68b1f0c2a4d3e50011aa22bb",
"trackId": "trk_abc123",
"status": "COMPLETED",
"processingStep": null,
"asset": "USDT",
"network": "polygon",
"address": "0x000000000000000000000000000000000000dEaD",
"value": 5000,
"valueInBrl": "50.00",
"fee": 100,
"feeInBrl": "1.00",
"fxRateAtTx": 5.55,
"receivedAmount": 8820000,
"receivedAmountDecimals": 6,
"transactionHash": "0xabc...",
"qrCode": "00020126...",
"endToEndId": "E1823612020260830120000000000001",
"paidAt": "2026-08-30T12:00:00.000Z",
"payer": {
"name": "FULANO DE TAL",
"taxId": "12345678901"
},
"confirmedAt": "2026-08-30T12:00:31.000Z",
"createdAt": "2026-08-30T11:59:02.000Z",
"updatedAt": "2026-08-30T12:00:31.000Z"
}
}Fields
| Field | Type | Description |
|---|---|---|
externalId | string | Your reconciliation key. |
walletCharge | string | Hodle id of the charge, the same one the POST returned. |
trackId | string | null | Hodle tracking id of the operation. |
status | string | PENDING, FIAT_PAID, PROCESSING, COMPLETED, FAILED, REFUNDED or EXPIRED. See below. |
processingStep | string | null | Where a PROCESSING deposit currently is. Report it, never route on it. |
asset | string | Asset being delivered. |
network | string | Network the asset is delivered on. |
address | string | Destination address of the delivery. |
value | integer | Amount in BRL cents. |
valueInBrl | string | Same amount, decimal string. |
fee | integer | Fee in BRL cents. |
feeInBrl | string | Same fee, decimal string. |
fxRateAtTx | number | null | Exchange rate at the time of the transaction. |
receivedAmount | integer | null | Amount actually delivered, in the asset's smallest unit. |
receivedAmountDecimals | integer | null | Decimals of receivedAmount. |
transactionHash | string | null | On-chain tx hash of the delivery, when there is one. |
qrCode | string | null | The PIX QR code / BR Code we handed you on creation. |
endToEndId | string | null | End-to-end id of the PIX that funded the deposit. null until it is paid. |
paidAt | string | null | ISO-8601 timestamp of when the PIX settled. |
payer | object | null | Who paid the PIX — see Who paid the QR code. |
confirmedAt | string | null | ISO-8601 timestamp of the delivery. |
createdAt | string | ISO-8601 creation timestamp. |
updatedAt | string | ISO-8601 timestamp of the last change. |
Status
| Status | Meaning |
|---|---|
PENDING | Charge created, PIX not paid yet. |
FIAT_PAID | Fiat payment received; the asset has not yet been delivered. paidAt and endToEndId are available. Keep polling. |
PROCESSING | Fiat payment received, asset delivery in progress. Keep polling. |
COMPLETED | Asset delivered. transactionHash is set when the rail produces one. |
FAILED | The deposit could not be delivered. |
EXPIRED | The charge expired without being paid. |
Who paid the QR code
payer carries the identity of whoever actually paid the PIX, as the payer's bank
reports it.
| Field | Type | Description |
|---|---|---|
name | string | null | Name of the payer. |
taxId | string | null | CPF/CNPJ of the payer, digits only. |
It is null when the PIX has not been paid yet, when the deposit was funded
through a rail that carries no payer, or when your account does not own a virtual
account. Only on your own virtual account is the payer your own customer; on the shared Hodle account they are our
counterparty and stay private. Ask support to enable it if you need it.
Errors
{
"success": false,
"error": "Deposit not found"
}A deposit that belongs to another API key answers 404, never 403, so the
status code cannot be used to probe for someone else's externalId.