Onramp intent
Move BRL into BRS tokens minted to a whitelisted wallet on Solana, Ethereum, Base or Polygon. Your backend creates the intent, Nora returns PIX deposit info, your user pays by PIX, and the tokens land.
An onramp intent is a single BRL → BRS mint. Your backend posts
the amount, the destination wallet, and the chain; Nora returns
PIX deposit info you surface to your user. Once the PIX lands, Nora
mints BRS to the wallet and the intent reaches completed.
Flow
Create the intent
POST /v2/intents/onramp
chainId accepts "solana", "ethereum", or "base". Base is live in both environments (sandbox = Base Sepolia, production = Base mainnet). It also accepts "polygon", live in both environments (sandbox = Polygon Amoy, production = Polygon mainnet).
| Field | Type | Required | Notes |
|---|---|---|---|
amountCents | integer | Yes | BRL amount in cents, not decimals. 100.00 BRL → 10000. Must be at least 500 (R$5.00 = 5 BRS minimum). |
destinationWallet | string | Yes | Wallet that receives the minted BRS: a Solana address, or an Ethereum address (0x…) registered through the Wallets API. 1–255 chars. |
chainId | string | Yes | "solana", "ethereum", "base", or "polygon". The intent is minted on that chain; destinationWallet must be a whitelisted wallet on it. |
clientReference | string | No | Your own correlation ID, up to 255 chars. Echoed on the intent. Unique per environment, forever, across onramp and offramp; when omitted, the idempotency-key is stored and echoed as the reference. |
Headers:
| Header | Value |
|---|---|
X-API-Key | Your API key. See Authentication. |
idempotency-key | Recommended. A UUID you pick (format-validated). Reuse on retries, regenerate on new user intents. See Idempotency. |
Example:
ORDER_KEY=$(uuidgen) # one per user order, reused on retries
curl -X POST https://sandbox.api.nora.finance/v2/intents/onramp \
-H "X-API-Key: $NORA_API_KEY" \
-H "Content-Type: application/json" \
-H "idempotency-key: $ORDER_KEY" \
-d '{
"amountCents": 10000,
"destinationWallet": "So11111111111111111111111111111111111111112",
"chainId": "solana",
"clientReference": "ord_123"
}'Response:
{
"id": "8f2a...",
"instanceId": "4e0b...",
"intentType": "onramp",
"flowVersion": 1,
"status": "awaiting_fiat_payment",
"statusReason": null,
"failureCode": null,
"providerFailureCode": null,
"originalFailureCode": null,
"originalProviderFailureCode": null,
"clientReference": "ord_123",
"metadata": { "chainId": "solana", "amountCents": 10000, "…": "…" },
"expiresAt": "2026-04-22T12:30:00Z",
"createdAt": "2026-04-22T12:00:00Z",
"updatedAt": "2026-04-22T12:00:00Z",
"pixPayment": {
"brcode": "00020101021126580014BR.GOV.BCB.PIX...",
"txid": "abc123",
"amountCents": 10000,
"expiresAt": "2026-04-22T12:30:00Z"
},
"depositInstructions": null,
"party": { "displayName": "Your Company", "documentMasked": "64***65", "solanaWallet": null },
"chainId": "solana"
}Notable response fields:
intentType—"onramp"here.flowVersion— integer; pin on at least the version your code was written against.status— see the lifecycle table below for the full enum.
Render the PIX instructions
Surface pixPayment to the user: render brcode as a scannable QR code and
a copy-and-paste field. amountCents and expiresAt provide the payment
amount and deadline. PIX deposits expire — if the user hasn't paid by
expiresAt, the intent transitions to expired and you need a new intent
to retry: a fresh idempotency-key and, if you send one, a fresh
clientReference (references are unique per environment, forever).
In the sandbox nobody pays: the deposit is simulated and the intent
moves to fiat_received on its own shortly after creation, then mints.
Track completion
Poll GET /v2/intents/:id or subscribe to webhooks. The full intent
status enum:
| Status | Terminal? | Notes |
|---|---|---|
created | no | Accepted server-side, not yet routed. |
requires_compliance | no | Held for compliance review. |
awaiting_fiat_payment | no | Waiting for the user's PIX. |
fiat_received | no | PIX confirmed by the rail. |
minting | no | BRS being minted on-chain. |
awaiting_onchain_transfer | no | |
awaiting_burn_approval | no | (offramp) — not seen on onramp. |
burn_approved | no | (offramp). |
onchain_received | no | |
burning | no | (offramp). |
scheduled | no | (offramp). |
paying_out | no | (offramp). |
completed | yes | Terminal success. |
expired | yes | PIX window closed before payment. |
canceled | yes | |
failed | no | Not terminal, but no automatic recovery: a refund is started by Nora's operators after review, never by an API call, and it may not start. Check failureCode; it can be null (for example when the destination was denied after the PIX was charged, see metadata.destinationAuthDenialCode), and then statusReason or metadata carries the cause. Contact Nora with the intent id. |
refunding | no | Nora is processing a refund. |
refunded | yes | Refund completed. |
Gotchas
amountCents, notamount. Integer cents, not decimal BRL.- Minimum R$5.00 (5 BRS).
amountCentsbelow500is rejected at creation with a400— the floor mirrors the on-chainMintConfig.min_amount.
- Idempotency keys scope to "this user intent," not "this retry." Regenerate on a new form submission, reuse across network-level retries. See Idempotency.
- Response
chainIdechoes the request ("solana","ethereum","base", or"polygon"). clientReferenceis unique per environment, forever. Reusing one answers409 Intent with clientReference 'ord_123' already exists, even when that intent expired. A retry with the sameidempotency-keyand body is replayed instead.- On Ethereum, Nora reads your whitelister and the BRS token on-chain
before charging. A
destinationWalletwith no authorization fails with400andmessage: "evm_destination_wallet_not_authorized"; one whose daily limit is belowamountCentsgetsevm_destination_wallet_rate_limit_exceeded; an amount outside the per-mint bounds getsevm_mint_amount_below_minimumorevm_mint_amount_above_maximum. Register the wallet through the Wallets API first. A completed Ethereum mint reportsstatusReason: "EVM mint confirmed on-chain."and the transaction hash atmetadata.mintTxSignature;metadatakeys are informational, not part of the versioned contract.
See also
- Offramp intent — the reverse direction (BRS → BRL)
- Ethereum end-to-end — the Ethereum mint inside the full flow, with real responses
- Idempotency — key lifecycle
- API Reference: Intents — full endpoint spec
- Intents in the dashboard — operator-side view
Wallet whitelisting
Register a minter wallet via /v2/wallets, sign the grant yourself, and activate it. Three paths - prepared, self-built, or EVM calldata.
Offramp intent
Redeem BRS tokens for a BRL payout via PIX. Your backend creates the intent, the token holder burns on Solana, Ethereum, Base or Polygon, and the payout settles.