Skip to main content
For authentication, error codes, and request conventions, see API Overview.

GET /v1/orchestration/routes

List all supported trading pairs. No authentication required. Response:
{
  "routes": [
    {
      "sourceChain": "base",
      "sourceAsset": "USDC",
      "destinationChain": "spark",
      "destinationAsset": "BTC"
    },
    {
      "sourceChain": "spark",
      "sourceAsset": "BTC",
      "destinationChain": "base",
      "destinationAsset": "USDC"
    }
  ]
}
Each entry is a valid (sourceChain, sourceAsset) -> (destinationChain, destinationAsset) pair that can be used with /estimate, /quote, and /submit. The list is derived from the pipeline route resolver and stays in sync automatically as new pairs are added.

GET /v1/orchestration/estimate

Lightweight price preview. This does not create a quote and does not write to the database. Query parameters:
ParamRequiredNotes
sourceChainYesOne of the supported chains
sourceAssetYesOne of the supported assets
destinationChainYesOne of the supported chains
destinationAssetYesOne of the supported assets
amountYesInteger string
Response:
{
  "estimatedOut": "string",
  "feeAmount": "string",
  "feeBps": 5,
  "feeAsset": "USDC",
  "route": ["USDC", "USDB", "BTC"]
}
feeAsset is USDC for most routes and USDB for BTC -> USDB.

POST /v1/orchestration/quote

Request a durable quote with deposit instructions. Quotes expire 30 minutes after creation. Exact-in example (default mode):
{
  "sourceChain": "base",
  "sourceAsset": "USDC",
  "destinationChain": "spark",
  "destinationAsset": "BTC",
  "amount": "100000000",
  "recipientAddress": "spark1...",
  "slippageBps": 50,
  "zeroconfEnabled": true
}
Exact-out payment-intent example (bitcoin:BTC -> base|solana:USDC):
{
  "sourceChain": "bitcoin",
  "sourceAsset": "BTC",
  "destinationChain": "base",
  "destinationAsset": "USDC",
  "amount": "100000000",
  "amountMode": "exact_out",
  "recipientAddress": "0xYourBaseUsdcAddress",
  "refundAddress": "bc1qyourrefundaddress...",
  "slippageBps": 0
}
Exact-out Lightning example (any buy-side source -> lightning:BTC):
{
  "sourceChain": "base",
  "sourceAsset": "USDC",
  "destinationChain": "lightning",
  "destinationAsset": "BTC",
  "amount": "100000",
  "amountMode": "exact_out",
  "recipientAddress": "lnbc1u1...",
  "refundAddress": "0xYourBaseUsdcRefundAddress",
  "slippageBps": 0
}
Exact-in affiliate-fee example (spark:BTC -> solana:USDC):
{
  "sourceChain": "spark",
  "sourceAsset": "BTC",
  "destinationChain": "solana",
  "destinationAsset": "USDC",
  "amount": "100000",
  "recipientAddress": "So1RecipientAddress...",
  "appFees": [
    {
      "recipient": "So1AffiliateOne...",
      "fee": 100
    },
    {
      "recipient": "So1AffiliateTwo...",
      "fee": 50
    }
  ]
}
Exact-in affiliate-registry example (spark:BTC -> solana:USDC):
{
  "sourceChain": "spark",
  "sourceAsset": "BTC",
  "destinationChain": "solana",
  "destinationAsset": "USDC",
  "amount": "100000",
  "recipientAddress": "So1RecipientAddress...",
  "affiliateId": "flashpartner"
}
Exact-in source-side affiliate-fee example (solana:SOL -> spark:BTC):
{
  "sourceChain": "solana",
  "sourceAsset": "SOL",
  "destinationChain": "spark",
  "destinationAsset": "BTC",
  "amount": "100000000",
  "recipientAddress": "spark1...",
  "appFees": [
    {
      "recipient": "Dtkxt55zEUDj6NTXGRtH8uQsACsTjoSVkXfYBEF8xkkT",
      "fee": 100
    }
  ]
}
Notes:
  • amountMode defaults to exact_in.
  • amountMode=exact_out is supported for bitcoin:BTC -> (base|solana):USDC and any buy-side source -> lightning:BTC.
  • refundAddress is required when amountMode=exact_out.
  • If Authorization is included, send X-Idempotency-Key.
  • appFees and affiliateId are currently supported only for amountMode=exact_in and when sourceChain or destinationChain is base|solana.
  • Fee settlement chain is sourceChain when source is base|solana, otherwise destinationChain.
  • appFees max length is 16.
  • Each appFees[i].fee is fee bps (1..10000).
  • Sum of all app fee bps must be <= 10000.
  • affiliateId must match ^[a-z0-9][a-z0-9_-]{0,63}$ after trimming and lowercasing.
  • Use either appFees or affiliateId, not both.
  • affiliateId requires authenticated quote requests.
  • slippageBps defaults to 50 when omitted.
  • zeroconfEnabled is only used when sourceChain = bitcoin and amountMode = exact_in.
    • If omitted, it defaults to true.
    • If the deployment does not have ZeroConf configured, the engine falls back to on-chain confirmations.
  • For destinationChain = lightning, recipientAddress must be a BOLT11 invoice. In exact_in mode, the invoice must be amountless (0-amount). In exact_out mode, the invoice can be amountless or encode an amount matching the requested amount in sats.
Affiliate fee models:
  • Inline recipients:
    • appFees: [{ recipient: string, fee: number }]
    • fee is fee bps per recipient (1..10000).
  • Registry by id:
    • affiliateId: string
    • profile is managed through PUT /v1/affiliates/:affiliateId
    • quote resolves recipient + fee bps from your partner-scoped profile
  • Settlement asset is always USDC.
  • Settlement chain is selected as:
    • sourceChain when source is base|solana
    • otherwise destinationChain (must be base|solana)
  • Execution point:
    • If source is base|solana, fees are deducted on the source-side USDC leg before bridge/swap continuation.
    • If source is not base|solana, fees are deducted on the destination-side USDC payout leg.
  • For source native routes like SOL -> BTC and ETH -> BTC, fees are still deducted on the source-side USDC leg after ingress conversion (SOL|ETH -> USDC).
  • Quote math order:
    • platform fee (feeAmount)
    • optional sweep fee (sweepFeeAmount, USDC-source routes only)
    • app fee allocation (appFeeAmount, appFees)
    • 20% platform cut retained from each app fee (appFeePlatformCutAmount); remaining 80% goes to the fee recipient
    • net amount proceeds to route execution
  • Flashnet retains 20% of each app/affiliate fee. The quote response shows the split per recipient: amount (gross fee charged to the user), platformCutAmount (20% retained by Flashnet), and recipientAmount (80% paid to the fee recipient).
  • appFees recipients are validated against the settlement-chain address format.
  • For affiliateId, the profile must have a recipient address for the quote settlement chain (base and/or solana).
Response (exact-out sample):
{
  "quoteId": "q_...",
  "depositAddress": "bc1q...",
  "amountIn": "250000",
  "estimatedOut": "100000000",
  "feeAmount": "100000",
  "totalFeeAmount": "100000",
  "feeAsset": "USDC",
  "feeBps": 5,
  "route": ["BTC", "USDB", "USDC"],
  "expiresAt": "2026-02-04T02:00:00.000Z",
  "zeroconfEnabled": false,
  "amountMode": "exact_out",
  "targetAmountOut": "100000000",
  "requiredAmountIn": "250000",
  "maxAcceptedAmountIn": "250050",
  "inputBufferBps": 2,
  "priceLockMode": "approval_required",
  "lockedMinAmountOut": "99900000"
}
Response (exact-in with appFees sample):
{
  "quoteId": "q_...",
  "depositAddress": "spark1...",
  "amountIn": "100000",
  "estimatedOut": "24825000",
  "feeAmount": "25000",
  "totalFeeAmount": "62125",
  "appFeeAmount": "37125",
  "appFeePlatformCutAmount": "7425",
  "appFees": [
    {
      "affiliateId": "flashpartner",
      "recipient": "So1AffiliateOne...",
      "feeBps": 50,
      "amount": "24750",
      "platformCutAmount": "4950",
      "recipientAmount": "19800"
    },
    {
      "recipient": "So1AffiliateTwo...",
      "feeBps": 50,
      "amount": "12375",
      "platformCutAmount": "2475",
      "recipientAmount": "9900"
    }
  ],
  "feeAsset": "USDC",
  "feeBps": 5,
  "route": ["BTC", "USDB", "USDC"],
  "expiresAt": "2026-02-04T02:00:00.000Z"
}
Response (exact-in source-side appFees sample):
{
  "quoteId": "q_...",
  "depositAddress": "So1DepositAddress...",
  "amountIn": "100000000",
  "estimatedOut": "11643",
  "feeAmount": "7893",
  "totalFeeAmount": "86749",
  "appFeeAmount": "78856",
  "appFeePlatformCutAmount": "15771",
  "appFees": [
    {
      "recipient": "Dtkxt55zEUDj6NTXGRtH8uQsACsTjoSVkXfYBEF8xkkT",
      "feeBps": 50,
      "amount": "78856",
      "platformCutAmount": "15771",
      "recipientAmount": "63085"
    }
  ],
  "feeAsset": "USDC",
  "feeBps": 5,
  "route": ["SOL", "USDC", "USDB", "BTC"],
  "expiresAt": "2026-02-11T23:55:36.296Z",
  "priceLockMode": "strict_requote",
  "lockedMinAmountOut": "11584"
}
Field notes:
  • depositAddress depends on sourceChain:
    • base|solana: chain address that receives the source asset
    • spark: Spark address that receives BTC or USDB
    • bitcoin: Bitcoin L1 address
    • lightning: BOLT11 invoice to pay
  • totalFeeAmount is returned when feeAsset is USDC and equals feeAmount + appFeeAmount + sweepFeeAmount (when present).
  • sweepFeeAmount is returned on some USDC-source routes when a sweep fee is configured, and is included in totalFeeAmount.
  • appFeeAmount and appFees are returned when appFees or affiliateId was requested.
  • appFeePlatformCutAmount is the sum of Flashnet’s 20% cut across all app fees.
  • appFees[*].amount is the gross fee in settlement-chain USDC smallest units (what the user pays).
  • appFees[*].platformCutAmount is Flashnet’s 20% cut of that fee.
  • appFees[*].recipientAmount is the 80% paid to the fee recipient.
  • appFees[*].affiliateId is present when the quote used affiliateId.
  • zeroconfEnabled is only present for sourceChain = bitcoin.
  • lightningReceiveRequestId is only present for sourceChain = lightning quotes.
  • feeAsset is USDB for BTC -> USDB quotes and USDC otherwise.
  • targetAmountOut, requiredAmountIn, maxAcceptedAmountIn, and inputBufferBps are present for exact-out quotes.
  • inputBufferBps is currently 2 when slippageBps=0, otherwise 0.
  • priceLockMode and lockedMinAmountOut are present for routes where a Flashnet min-out lock is enforced.

POST /v1/orchestration/submit

Create an order from a quote after you have initiated the source deposit. Headers:
Authorization: Bearer fn_...
X-Idempotency-Key: <unique key>
Request body shape depends on the quote sourceChain. Base/Solana sources (sourceChain = base|solana):
{
  "quoteId": "q_...",
  "txHash": "0x...",
  "sourceAddress": "0x..."
}
sourceAddress is optional but recommended. It is required when depositing to a shared address. When present, deposit verification requires the sender to match. Spark sources (sourceChain = spark):
{
  "quoteId": "q_...",
  "sparkTxHash": "spark_transfer_id_or_token_tx_hash",
  "sourceSparkAddress": "spark1..."
}
sourceSparkAddress is optional but recommended. It is required when depositing to a shared Spark address. When present, deposit verification requires the sender to match. Bitcoin L1 sources (sourceChain = bitcoin):
{
  "quoteId": "q_...",
  "bitcoinTxid": "txid"
}
bitcoinVout is optional. When omitted, the engine resolves it by scanning the transaction outputs for the one that pays the quote’s deposit address. You can still provide it explicitly if needed. Lightning sources (sourceChain = lightning):
{
  "quoteId": "q_...",
  "lightningReceiveRequestId": "string"
}
lightningReceiveRequestId can be omitted. When omitted, the API uses the value embedded in the quote. The txHash field is validated per source chain:
  • Base: 0x-prefixed 64-character hex string
  • Solana: Base58-encoded signature (64-90 characters)
  • Bitcoin: 64-character hex transaction ID
  • Spark: UUID format, 32-character hex, or 64-character token transaction hash
  • Lightning: Automatically populated from the quote’s receive request ID
Response:
{
  "orderId": "ord_...",
  "status": "processing"
}
If an order already exists for the same (sourceChain, sourceTxHash[, sourceTxVout]), submit returns the existing { orderId, status }.

POST /v1/orchestration/onramp

Combined quote and submit for Lightning sell flows. Creates a Lightning invoice and order in a single call. Designed for fiat onramp integrations where the user pays via Cash App. The source is always lightning:BTC. The amount field is BTC in sats. Headers:
Authorization: Bearer fn_...
X-Idempotency-Key: <unique key>
Request body:
{
  "destinationChain": "solana",
  "destinationAsset": "USDC",
  "recipientAddress": "So1...",
  "amount": "100000",
  "slippageBps": 50
}
FieldRequiredNotes
destinationChainYesTarget chain
destinationAssetYesTarget asset
recipientAddressYesAddress on the destination chain
amountYesBTC in sats (integer string)
slippageBpsNoDefault 50
appFeesNoInline affiliate fees
affiliateIdNoRegistered affiliate ID
Response:
{
  "orderId": "op_...",
  "quoteId": "q_...",
  "depositAddress": "lnbc1000n1pj...",
  "paymentLinks": {
    "cashApp": "https://cash.app/launch/lightning/lnbc1000n1pj...",
    "shortUrl": "https://orchestration.flashnet.xyz/pay/a3xKm2Rq"
  },
  "amountIn": "100000",
  "estimatedOut": "96543210",
  "feeAmount": "4830",
  "feeBps": 5,
  "totalFeeAmount": "4830",
  "feeAsset": "USDC",
  "route": ["verify-lightning-deposit", "flashnet-swap-btc-to-usdb", "bridge-usdb-to-usdc", "deliver-solana-usdc"],
  "expiresAt": "2025-01-15T12:04:00.000Z"
}
The paymentLinks.cashApp URL is a deeplink that opens Cash App to pay the Lightning invoice. On mobile, redirect the user to this URL. On desktop, display it as a QR code. paymentLinks.shortUrl is a short redirect URL that 302s to the Cash App deeplink. Use this when sharing payment links in text messages, emails, or other contexts where the full Cash App URL is too long. The short URL is always present when PUBLIC_BASE_URL is configured on the server. The Lightning invoice expires at expiresAt (2 minutes from creation). If the user doesn’t pay in time, create a new onramp order. For the full integration guide with code examples, see Fiat Onramp.

GET /v1/orchestration/order

Look up a quote and its associated order by quote ID. Designed for submissionless flows where partners poll after creating a quote and directing a user to deposit. Returns the quote state alongside the order. When no order exists yet (deposit not detected), order is null and the quote’s expired field indicates whether the deposit window is still open. Headers:
Authorization: Bearer fn_...
Query parameters:
ParamRequiredNotes
quoteIdYesQuote id (q_...)
Response when no order exists yet:
{
  "quote": {
    "id": "q_...",
    "kind": "sell",
    "sourceChain": "spark",
    "sourceAsset": "BTC",
    "destinationChain": "solana",
    "destinationAsset": "USDC",
    "amountIn": "100000",
    "estimatedOut": "96500000",
    "feeBps": 5,
    "feeAmount": "4830",
    "depositAddress": "spark1...",
    "recipientAddress": "So1...",
    "slippageBps": 50,
    "expiresAt": "2026-02-04T02:00:00.000Z",
    "expired": false,
    "createdAt": "2026-02-04T01:58:00.000Z"
  },
  "order": null,
  "stages": []
}
Response when an order has been created:
{
  "quote": {
    "id": "q_...",
    "kind": "sell",
    "sourceChain": "spark",
    "sourceAsset": "BTC",
    "destinationChain": "solana",
    "destinationAsset": "USDC",
    "amountIn": "100000",
    "estimatedOut": "96500000",
    "feeBps": 5,
    "feeAmount": "4830",
    "depositAddress": "spark1...",
    "recipientAddress": "So1...",
    "slippageBps": 50,
    "expiresAt": "2026-02-04T02:00:00.000Z",
    "expired": true,
    "createdAt": "2026-02-04T01:58:00.000Z"
  },
  "order": {
    "id": "ord_...",
    "type": "order",
    "status": "swapping",
    "quoteId": "q_...",
    "sourceChain": "spark",
    "sourceAsset": "BTC",
    "destinationChain": "solana",
    "destinationAsset": "USDC",
    "recipientAddress": "So1...",
    "amountIn": "100000",
    "amountOut": null,
    "feeBps": 5,
    "feeAmount": "4830",
    "createdAt": "2026-02-04T02:01:00.000Z"
  },
  "stages": [
    {
      "name": "deposit_confirmed",
      "status": "completed",
      "completedAt": "2026-02-04T02:01:05.000Z"
    }
  ]
}
The order object uses the same shape as GET /v1/orchestration/status, including optional swap, priceLock, reprice, paymentIntent, zeroconfOffer, feePlan, and feePayouts metadata when present. Polling pattern for submissionless flows:
  1. Create a quote via POST /v1/orchestration/quote.
  2. Direct the user to deposit to depositAddress.
  3. Poll GET /v1/orchestration/order?quoteId=q_... until order is non-null.
  4. Once order appears, continue polling or switch to webhooks to track execution.
When quote.expired is true and order is still null, the deposit window has closed. Expired quotes that receive a late deposit are repriced at live market rates and still create an order.

GET /v1/orchestration/status

Check an order’s current state. Authentication is optional:
  • Without Authorization: returns a redacted order record.
  • With Authorization: returns the full order record for your partner only.
Provide exactly one query parameter:
ParamNotes
idOrder id (ord_...)
quoteIdQuote id (q_...)
txHashSource transaction identifier (see order.sourceTxHash)
txHash lookup returns the most recently created order with that sourceTxHash. For Bitcoin L1 deposits where multiple orders can share the same txid, prefer id from webhooks for exact attribution. Possible order.status values:
  • processing
  • confirming
  • bridging
  • swapping
  • awaiting_approval
  • refunding
  • delivering
  • completed
  • failed
  • refunded
Response (authenticated):
{
  "order": {
    "id": "ord_...",
    "type": "order",
    "status": "awaiting_approval",
    "quoteId": "q_...",
    "sourceChain": "bitcoin",
    "sourceAsset": "BTC",
    "sourceAddress": null,
    "sourceTxHash": "<txid>",
    "sourceTxVout": 0,
    "depositAddress": "bc1q...",
    "destinationChain": "base",
    "destinationAsset": "USDC",
    "recipientAddress": "0x...",
    "amountIn": "250000",
    "amountOut": null,
    "feeBps": 5,
    "feeAmount": "100000",
    "slippageBps": 0,
    "errorCode": "reprice_approval_required",
    "errorMessage": "Received 249900 sats, requires at least 250000 sats",
    "createdAt": "2026-02-04T01:30:00.000Z",
    "updatedAt": "2026-02-04T01:30:10.000Z",
    "completedAt": null,
    "priceLock": {
      "version": 1,
      "mode": "approval_required",
      "amountIn": "250000",
      "quotedAmountOut": "100100000",
      "lockedMinAmountOut": "100000000",
      "slippageBps": 0,
      "createdAt": "2026-02-04T01:00:00.000Z",
      "expiresAt": "2026-02-04T01:30:00.000Z"
    },
    "reprice": {
      "version": 1,
      "status": "awaiting_approval",
      "previousLockedMinAmountOut": "100000000",
      "proposedMinAmountOut": "99800000",
      "latestExpectedAmountOut": "99800000",
      "requestedAt": "2026-02-04T01:30:10.000Z",
      "resolvedAt": null,
      "reason": "insufficient_input"
    },
    "paymentIntent": {
      "version": 1,
      "amountMode": "exact_out",
      "targetAmountOut": "100000000",
      "requiredAmountIn": "250000",
      "maxAcceptedAmountIn": "250050",
      "inputBufferBps": 2,
      "actualAmountIn": "249900",
      "refundAddress": "bc1q...",
      "exactOutExecution": "strict"
    },
    "feePlan": {
      "version": 1,
      "settlementChain": "solana",
      "settlementAsset": "USDC",
      "appFees": [
        {
          "affiliateId": "flashpartner",
          "recipient": "So1AffiliateOne...",
          "feeBps": 50
        },
        {
          "recipient": "So1AffiliateTwo...",
          "feeBps": 50
        }
      ]
    },
    "feePayouts": {
      "version": 1,
      "entries": [
        {
          "idempotencyKey": "order:ord_...:full:appfee:0",
          "leg": "full",
          "chain": "solana",
          "role": "app_fee",
          "affiliateId": "flashpartner",
          "recipient": "So1AffiliateOne...",
          "feeBps": 50,
          "amount": "24750",
          "platformCutAmount": "4950",
          "recipientAmount": "19800",
          "txHash": "5kW...",
          "recordedAt": "2026-02-04T01:35:00.000Z"
        },
        {
          "idempotencyKey": "order:ord_...:full:payout",
          "leg": "full",
          "chain": "solana",
          "role": "recipient_payout",
          "recipient": "So1RecipientAddress...",
          "feeBps": null,
          "amount": "2475000",
          "platformCutAmount": null,
          "recipientAmount": null,
          "txHash": "3hN...",
          "recordedAt": "2026-02-04T01:35:02.000Z"
        }
      ]
    }
  },
  "stages": [
    {
      "name": "deposit_confirmed",
      "status": "completed",
      "completedAt": "2026-02-04T01:30:05.000Z"
    },
    {
      "name": "reprice_requested",
      "status": "completed",
      "completedAt": "2026-02-04T01:30:10.000Z"
    }
  ]
}
With Authorization, the order object is the full public operation record. Without it, some fields are omitted. amountIn and feeAmount reflect the actual processed deposit. When the on-chain deposit differs from the original quote, the engine updates these fields before execution. Any positive deposit amount is accepted. The stages array will include amount_reconciled when this adjustment occurred. Depending on route and progress, the order can include:
  • flashnetRequestId when a Flashnet swap has executed
  • sparkTxHash when a Spark transfer, withdrawal, or Lightning action is created
  • swap metadata when a Flashnet swap leg has been recorded
  • priceLock, reprice, and paymentIntent metadata for locked/approval-required flows
  • zeroconfOffer when a ZeroConf offer has been generated for a Bitcoin L1 deposit (see ZeroConf offer fields)
  • feePlan when quote-level appFees or affiliateId was requested
  • feePayouts as affiliate and recipient payout legs are executed
  • feePayouts.entries[*].role is app_fee or recipient_payout
  • feePayouts.entries[*].affiliateId is present for app-fee entries derived from affiliateId
  • feePayouts.entries[*].leg is full, instant, or holdback for routes that execute in multiple legs

GET /v1/orchestration/history

List your orders filtered by recipientAddress. Headers:
Authorization: Bearer fn_...
Query parameters:
ParamRequiredNotes
addressYesRecipient address (Spark address, Bitcoin address, Lightning invoice, or Base/Solana address depending on the route)
statusNoExact match on the order status
limitNoDefault 50, max 200
offsetNoDefault 0
Response:
{
  "orders": [{ "id": "ord_...", "status": "completed" }]
}
History entries use the same order shape as GET /v1/orchestration/status, including optional swap, priceLock, reprice, paymentIntent, and zeroconfOffer metadata when present.