nora

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:

FieldTypeNotes
idstring (uuid)
instanceIdstring (uuid)
intentType"onramp" | "offramp"
flowVersionintegerPin on at least the version your code was written against.
adapter"squads" | "cuiaba" | null
statussee status enum
statusReasonstring | null
clientReferencestring | nullEchoed from your body.
metadataobject | null
expiresAtstring | nullISO 8601.
createdAtstringISO 8601.
updatedAtstring
pixInfoobject | nullPIX deposit info on onramps; null on offramps.
depositInstructionsnullAlways null in the current /v2 response.
chainId"solana"Today the response enum is Solana-only even though requests accept "polygon".

pixInfo when present:

FieldTypeNotes
keyType"cnpj"Only value today.
keyValuestring
recipientNamestring
bankstring
descriptionstring
amountCentsinteger

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

HeaderRequiredNotes
X-API-KeyYes
Content-TypeYesapplication/json
idempotency-keyRecommendedUUID (format-validated). One key per user intent; reuse across retries.

Request body

FieldTypeRequiredDescription
amountCentsintegerYesBRL amount in cents. Must be > 0.
destinationWalletstringYesSolana address (1–255 chars).
chainIdstringYes"solana" or "polygon" accepted on request.
clientReferencestringNoUp to 255 chars. Echoed on the intent.

Response 200 / 201

The intent response shape above.

Example

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: $(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

HeaderRequiredNotes
X-API-KeyYes
Content-TypeYesapplication/json
idempotency-keyRecommendedUUID (format-validated).

Request body

FieldTypeRequiredDescription
amountCentsintegerYesBRL payout amount in cents. Must be > 0.
destinationAddressstringYesFiat rail destination (PIX key, 1–255 chars).
chainIdstringYes"solana" or "polygon".
clientReferencestringNoUp to 255 chars.

Response 200 / 201

The intent response shape above. pixInfo is null on offramps and depositInstructions is always null.

Example

curl -X POST https://sandbox.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

ParamTypeRequired
idstring (uuid)Yes

Headers

HeaderRequired
X-API-KeyYes

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

HeaderRequired
X-API-KeyYes

Query parameters

ParameterTypeDefaultDescription
intentTypestring"all""onramp", "offramp", or "all".
statusstring"all"Any intent status (see enum above) or "all".
limitnumber501–100.
offsetnumber0Zero-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

ParamTypeRequired
idstring (uuid)Yes

Headers

HeaderRequiredNotes
X-API-KeyYes
Content-TypeYesapplication/json

No separate idempotency-key header — the on-chain txSignature is the dedup key.

Request body

FieldTypeRequiredDescription
txSignaturestringYesBase58-encoded signature (min length 1).
tokenHolderstringYesThe wallet'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.

On this page