Skip to content

Intent

How to lock a rate with a firm quote and execute it by submitting an Intent.

Submission is single-step: the response is terminal — accepted (execution begins immediately) or rejected (with a reason). There is no separate confirm step; rate certainty comes from attaching a firm quote to the Intent instead.

Flow

① POST /v1/quotes/firm            → quoteId + locked rate, fees, validUntil
② POST /v1/intents (+ quoteId)    → accepted  → settlement begins
                                  → rejected  (reason)
③ Track via webhooks / Status API

The firm quote is optional — an Intent submitted without a quoteId is a best-effort auction order that solvers compete to fill (and may expire unfilled). Attach a quoteId when you need the rate and fees locked. See Quote API → Firm quotes.

Step 1: Lock a rate (firm quote)

Request a firm quote for what you want to exchange. amountType: "target" fixes the recipient amount — the solver computes the required input including fees, so the recipient is never short-paid.

POST /v1/quotes/firm
json
{
  "requestId": "RFQ-FIRM-001",
  "actorId": "your-partner-id",
  "side": "sell",
  "inputAsset": { "type": "erc20", "symbol": "USDC", "chain": "ethereum" },
  "outputAsset": { "type": "fiat", "symbol": "USD", "currency": "USD" },
  "amountMinor": "1000000",
  "amountType": "target"
}

The response is returned directly (no { success, data } wrapper) and carries everything you need to decide:

jsonc
{
  "requestId": "RFQ-FIRM-001",
  "quoteId": "fq_9ab32c1f",                  // ← attach this to the Intent to execute
  "pair": "USDC/USD",
  "allInRate": "1.000000",
  "input":  { "amountMinor": "10010250000", "currency": "USDC", "exponent": 6 },
  "output": { "amountMinor": "1000000",     "currency": "USD",  "exponent": 2 },
  "fees": [
    { "type": "protocol_fee", "amountMinor": "1000",   "currency": "USD",  "exponent": 2, "collection": "deducted" },
    { "type": "payout_fee",   "amountMinor": "25",     "currency": "USD",  "exponent": 2, "collection": "deducted" },
    { "type": "network_fee",  "amountMinor": "0",      "currency": "USDC", "exponent": 6, "collection": "absorbed" }
  ],
  "validUntil": "2026-07-15T12:00:30Z"
}

At this point, nothing has been executed. The quoting LP has committed the rate and itemized fees until validUntil — you can review the locked terms and decide whether to proceed. See Quote API → Firm Quote Response for field details.

Step 2: Submit the Intent

Submitting the Intent is the acceptance of the quote — it must arrive before validUntil.

POST /v1/intents

Send an X-Idempotency-Key header (a UUID) so a lost response can be retried safely — see Idempotency. Use clientReference for your own correlation key; it is echoed verbatim on every read surface (status, webhooks, receipts).

json
{
  "intentId": "INT-9C1D2E3F",
  "clientReference": "your-payment-id-123",
  "user": "0xabc...def",
  "inputAsset": { "type": "erc20", "symbol": "USDC", "chain": "ethereum", "address": "0xA0b8...eB48" },
  "outputAsset": { "type": "fiat", "symbol": "USD", "currency": "USD" },
  "input": { "limitAmountMinor": "10100000000" },
  "output": { "targetAmountMinor": "1000000", "limitAmountMinor": "1000000" },
  "quoteId": "fq_9ab32c1f",
  "deadline": 1737123456789,
  "settlementType": "hybrid",
  "outputRecipient": "us-bank-account-123",
  "beneficiary": { "account": "110-123-456789", "name": "Jane Doe", "bank": "..." },
  "permit": {
    "token": "0xA0b8...eB48",
    "amountMinor": "10100000000",
    "spender": "0x1c9E...F63a",
    "nonce": "0",
    "deadline": 1737209856,
    "signature": "0x9f2c...8b1c"
  }
}

Two fields deserve attention:

  • permit — required for on-chain (erc20) inputs. A signed NfxPermit2 authorization that lets settlement pull the input from user's wallet; without it the Intent is rejected with permit_required. See Intent API → Permit.
  • beneficiary — required for any fiat output, and for remittances (outputRecipientuser).

Accepted

Responds 202 Accepted with the execution plan, returned directly (no envelope). On acceptance the solver reserves liquidity and settlement starts immediately:

json
{
  "intentId": "INT-9C1D2E3F",
  "status": "accepted",
  "planId": "DVP-INT-9C1D",
  "solverId": "solver-1",
  "inputAmountMinor": "10010250000",
  "fees": [ ... ],
  "path": {
    "outputAmountMinor": "1000000",
    "surplusAmountMinor": "0",
    "estimatedFillTime": 3600,
    "steps": [ ... ]
  }
}

With a quoteId attached, top-level fees is itemized from the locked quote — the receipt must later match it per fee type. See Intent API → Accepted Response for every field.

Rejected

A business rejection responds 422 with the original rejection object:

json
{
  "intentId": "INT-9C1D2E3F",
  "status": "rejected",
  "reason": "no_liquidity"
}

A rejected Intent never starts executing — nothing to cancel or compensate. See Intent API → Rejected Response for the full list of reasons, and Error Handling & Retries for which errors are safe to retry.

Step 3: Track execution

After acceptance, settlement proceeds asynchronously through three phases — intent → offramp → payout. Track it by:

  • Webhooks (push) — status events delivered to your endpoint; see Webhooks.
  • Status API (pull) — GET /v1/executions/{reference}, resolvable by your own clientReference; see Status API (coming soon — published as the contract of record ahead of rollout).

Both surfaces read from the same store and never disagree. On a timeout or missed event, re-query the Status API rather than re-submitting.

Handling expiry

A firm quote lapses at validUntil. An Intent that arrives after that is rejected, never silently re-priced — request a fresh firm quote and submit again. There is no quote re-fetch endpoint; quotes are short-lived by design.

Cancellation

There is no DELETE on the Intent endpoint — submission is terminal, and an accepted Intent is already executing. Cancellation happens through other channels:

  • FIX (institutional): an OrderCancelRequest (35=F) cancels the intent.
  • On-chain: an Intent can be cancelled permissionlessly once its fill deadline has passed.

See Intent API → Cancellation.

Full API Reference

For complete field descriptions, amount-bounds semantics, and error codes, see the Intent API and Quote API.