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)
partyIdstring (uuid)Resolved by Nora from destinationWallet (onramp) or the wallet binding (offramp).
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.
partyobject | null{ displayName, documentMasked, solanaWallet } subset for convenience.
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). Must match a party's bound wallet.
chainIdstringYes"solana" or "polygon" accepted on request.
clientReferencestringNoUp to 255 chars. Echoed on the intent.

No partyId in the body. Nora resolves the party from destinationWallet.

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

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.

No partyId in 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

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 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.

On this page