Intents
Create onramp / offramp intents, fetch and list them, submit the SPL Approve signature for offramps.
Intents are the state-tracked transactions between your end-users' fiat
and on-chain balances. Two flavours: onramp (fiat → crypto) and
offramp (crypto → fiat). Offramps additionally require a
client-side SPL Approve signature, submitted back to Nora via
approve-burn.
Error envelope
All intents endpoints return errors in the intents-family shape:
{
"code": "machine_readable",
"message": "human-readable",
"validationErrors": [
{ "field": "amountCents", "message": "must be > 0" }
],
"details": { }
}code and message are always present on non-2xx responses.
validationErrors is populated on structural 400s. details is
optional and endpoint-specific. See
Error handling.
The intent response shape
Create (200/201), fetch (200), and the items inside list
(200) all return the same intent object:
| Field | Type | Notes |
|---|---|---|
id | string (uuid) | |
instanceId | string (uuid) | |
partyId | string (uuid) | Resolved by Nora from destinationWallet (onramp) or the wallet binding (offramp). |
intentType | "onramp" | "offramp" | |
flowVersion | integer | Pin on at least the version your code was written against. |
adapter | "squads" | "cuiaba" | null | |
status | see status enum | |
statusReason | string | null | |
clientReference | string | null | Echoed from your body. |
metadata | object | null | |
expiresAt | string | null | ISO 8601. |
createdAt | string | ISO 8601. |
updatedAt | string | |
pixInfo | object | null | PIX deposit info on onramps; null on offramps. |
depositInstructions | null | Always null in the current /v2 response. |
party | object | null | { displayName, documentMasked, solanaWallet } subset for convenience. |
chainId | "solana" | Today the response enum is Solana-only even though requests accept "polygon". |
pixInfo when present:
| Field | Type | Notes |
|---|---|---|
keyType | "cnpj" | Only value today. |
keyValue | string | |
recipientName | string | |
bank | string | |
description | string | |
amountCents | integer |
Status enum
created, requires_compliance, awaiting_fiat_payment,
fiat_received, minting, awaiting_onchain_transfer,
awaiting_burn_approval, burn_approved, onchain_received,
burning, paying_out, completed, expired, canceled, failed,
refunded.
POST /v2/intents/onramp
Create an onramp intent. The response includes pixInfo to surface to
your user.
Headers
| Header | Required | Notes |
|---|---|---|
X-API-Key | Yes | |
Content-Type | Yes | application/json |
idempotency-key | Recommended | UUID (format-validated). One key per user intent; reuse across retries. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
amountCents | integer | Yes | BRL amount in cents. Must be > 0. |
destinationWallet | string | Yes | Solana address (1–255 chars). Must match a party's bound wallet. |
chainId | string | Yes | "solana" or "polygon" accepted on request. |
clientReference | string | No | Up to 255 chars. Echoed on the intent. |
No
partyIdin the body. Nora resolves the party fromdestinationWallet.
Response 200 / 201
The intent response shape above.
Example
curl -X POST https://staging.api.nora.finance/v2/intents/onramp \
-H "X-API-Key: $NORA_API_KEY" \
-H "Content-Type: application/json" \
-H "idempotency-key: $(uuidgen)" \
-d '{
"amountCents": 10000,
"destinationWallet": "So11111111111111111111111111111111111111112",
"chainId": "solana",
"clientReference": "ord_123"
}'Errors
400— body validation (negative amount, missing field, address format).409— idempotency-key collision with a different body.
POST /v2/intents/offramp
Create an offramp intent. Once created, the user must sign an SPL
Approve and submit the txSignature via approve-burn. See
Burn signing.
Headers
| Header | Required | Notes |
|---|---|---|
X-API-Key | Yes | |
Content-Type | Yes | application/json |
idempotency-key | Recommended | UUID (format-validated). |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
amountCents | integer | Yes | BRL payout amount in cents. Must be > 0. |
destinationAddress | string | Yes | Fiat rail destination (PIX key, 1–255 chars). |
chainId | string | Yes | "solana" or "polygon". |
clientReference | string | No | Up to 255 chars. |
No
partyIdin the body. Nora resolves the party from the wallet binding on file.
Response 200 / 201
The intent response shape above. pixInfo is null on offramps and
depositInstructions is always null.
Example
curl -X POST https://staging.api.nora.finance/v2/intents/offramp \
-H "X-API-Key: $NORA_API_KEY" \
-H "Content-Type: application/json" \
-H "idempotency-key: $(uuidgen)" \
-d '{
"amountCents": 10000,
"destinationAddress": "user@example.com",
"chainId": "solana",
"clientReference": "payout_xyz_42"
}'Errors
400— body validation.409— idempotency-key collision.
GET /v2/intents/:id
Fetch a single intent by id.
Path parameters
| Param | Type | Required |
|---|---|---|
id | string (uuid) | Yes |
Headers
| Header | Required |
|---|---|
X-API-Key | Yes |
Response 200
The intent response shape above.
Errors
404— no intent with that id in this org/instance.
GET /v2/intents
List intents — filterable and paginated with limit / offset.
Headers
| Header | Required |
|---|---|
X-API-Key | Yes |
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
intentType | string | "all" | "onramp", "offramp", or "all". |
status | string | "all" | Any intent status (see enum above) or "all". |
limit | number | 50 | 1–100. |
offset | number | 0 | Zero-based. |
Response 200
{
"intents": [
{ "id": "…", "status": "…", "…": "…" }
],
"total": 42,
"limit": 50,
"offset": 0
}Pagination is offset-based (not cursor-based). The key is intents
(plural), not items. total is the full match count for the
filter.
POST /v2/intents/:id/approve-burn
Submit the SPL Approve transaction signature for an offramp intent.
Path parameters
| Param | Type | Required |
|---|---|---|
id | string (uuid) | Yes |
Headers
| Header | Required | Notes |
|---|---|---|
X-API-Key | Yes | |
Content-Type | Yes | application/json |
No separate
idempotency-keyheader — the on-chaintxSignatureis the dedup key.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
txSignature | string | Yes | Base58-encoded signature (min length 1). |
tokenHolder | string | Yes | The party's ATA for the BRS mint (32–44 chars). |
Response 200
{ "status": "burn_approved" }Single field — no intent echo. Re-fetch GET /v2/intents/:id to
observe subsequent transitions.
Errors
400— body validation, signature verification failure, wrong signer / wrong delegation amount.404— intent not found.