Skip to main content
This flow starts with a BTC (or USDB) deposit and ends with USDC, USDT, ETH, SOL, or TRX delivered to any supported chain. If you want a reusable Bitcoin address that runs this flow automatically on each deposit, use Liquidation Addresses. Common uses:
  • Merchant settlement: accept BTC and deliver stablecoins to any supported chain.
  • Wallet sell flow: users sell BTC and receive stablecoins, ETH, SOL, or TRX on their preferred chain.
  • Exact-out payments: deliver a precise USDC amount for invoices (Bitcoin L1 only). For exact-out BTC delivery to Lightning, see Stablecoin to BTC.
  • BTC (spark) -> USDC/USDT/ETH (ethereum|arbitrum|optimism|base), USDC (polygon), SOL (solana), TRX/USDT (tron), USDT (plasma), USDC (solana)
  • BTC (bitcoin|lightning) -> same destinations as spark BTC
  • BTC (bitcoin|lightning) -> USDB (spark)
  • USDB (spark) -> same destinations as spark BTC
Exact-out payment mode is supported on BTC (bitcoin) -> USDC (base|solana). For exact-out BTC delivery to Lightning, see Stablecoin to BTC.Affiliate fee settlement (appFees, affiliateId, or affiliateIds) requires amountMode = exact_in.

Flow

  1. Create a quote: POST /v1/orchestration/quote.
  2. Initiate the source deposit to depositAddress.
  3. Submit the deposit transaction identifier: POST /v1/orchestration/submit.
  4. Track status via webhooks or GET /v1/orchestration/status?id=....
  5. If status becomes awaiting_approval, check whether order.zeroconfOffer or order.reprice is present and resolve accordingly (see below).
Quotes expire 2 minutes after creation.

Example: BTC (Spark) to USDC (Base)

const BASE_URL = 'https://orchestration.flashnet.xyz';

const quote = await fetch(`${BASE_URL}/v1/orchestration/quote`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: `Bearer ${process.env.FLASHNET_API_KEY}`,
    'X-Idempotency-Key': `quote:${Date.now()}`,
  },
  body: JSON.stringify({
    sourceChain: 'spark',
    sourceAsset: 'BTC',
    destinationChain: 'base',
    destinationAsset: 'USDC',
    amount: '1000000',
    recipientAddress: '0xYourBaseUsdcAddress',
    slippageBps: 50,
  }),
}).then((r) => r.json());

// Send BTC on Spark to quote.depositAddress for quote.amountIn.
// Capture the Spark transfer id.
const sparkTransferId = await sendSparkBtc({
  toSparkAddress: quote.depositAddress,
  amountSats: quote.amountIn,
});

const submit = await fetch(`${BASE_URL}/v1/orchestration/submit`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    Authorization: `Bearer ${process.env.FLASHNET_API_KEY}`,
    'X-Idempotency-Key': `submit:${quote.quoteId}:${sparkTransferId}`,
  },
  body: JSON.stringify({
    quoteId: quote.quoteId,
    sparkTxHash: sparkTransferId,
    // Optional but recommended. When present, the deposit verifier checks the sender Spark address.
    sourceSparkAddress: 'spark1YourSenderAddress',
  }),
}).then((r) => r.json());

const status = await fetch(
  `${BASE_URL}/v1/orchestration/status?id=${encodeURIComponent(submit.orderId)}`,
).then((r) => r.json());

console.log(status.order.status);

Example: BTC (Bitcoin L1) to USDC (Exact In)

A Bitcoin L1 quote returns a Bitcoin depositAddress. After you broadcast the transaction, submit the txid. The engine automatically finds the output that paid the deposit address. Quote request:
{
  "sourceChain": "bitcoin",
  "sourceAsset": "BTC",
  "destinationChain": "solana",
  "destinationAsset": "USDC",
  "amount": "250000",
  "recipientAddress": "So1...",
  "slippageBps": 50,
  "zeroconfEnabled": true
}
Submit request:
{
  "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 for batched transactions where you want to specify a particular output.

Example: BTC (Bitcoin L1) to USDC (Exact Out Payment Intent)

Use exact-out when the destination must receive a precise USDC amount. Quote request:
{
  "sourceChain": "bitcoin",
  "sourceAsset": "BTC",
  "destinationChain": "base",
  "destinationAsset": "USDC",
  "amount": "100000000",
  "amountMode": "exact_out",
  "recipientAddress": "0xYourBaseUsdcAddress",
  "refundAddress": "bc1qyourrefundaddress...",
  "slippageBps": 0
}
Quote response adds:
  • targetAmountOut: requested destination amount
  • requiredAmountIn: minimum BTC input required
  • maxAcceptedAmountIn: highest BTC input auto-accepted
  • inputBufferBps: currently 2 when slippageBps=0, else 0
Deposit guidance:
  • Send requiredAmountIn for the cleanest path.
  • Keep actual input at or below maxAcceptedAmountIn.
  • If actual input is outside bounds, or target output cannot be met at current market conditions, the order moves to awaiting_approval.
Approval resolution endpoints:
  • POST /v1/orchestration/reprice/approve
  • POST /v1/orchestration/reprice/reject
  • POST /v1/orchestration/reprice/refund
reprice/refund moves the order to refunding, then terminal refunded after the refund is broadcast and recorded.

Example: BTC (Spark) to USDC (Solana) with Affiliate Fees

{
  "sourceChain": "spark",
  "sourceAsset": "BTC",
  "destinationChain": "solana",
  "destinationAsset": "USDC",
  "amount": "100000",
  "recipientAddress": "So1RecipientAddress...",
  "appFees": [
    {
      "recipient": "So1AffiliateOne...",
      "fee": 100
    },
    {
      "recipient": "So1AffiliateTwo...",
      "fee": 50
    }
  ]
}

Example: BTC (Spark) to USDC (Solana) with Affiliate Registry

{
  "sourceChain": "spark",
  "sourceAsset": "BTC",
  "destinationChain": "solana",
  "destinationAsset": "USDC",
  "amount": "100000",
  "recipientAddress": "So1RecipientAddress...",
  "affiliateId": "flashpartner"
}
Affiliate fees are settled in USDC on the destination payout side. Flashnet retains a 20% platform cut; the remaining 80% goes to the fee recipient. See Quotes and Orders for the full affiliate fee model, response fields, and settlement behavior.

Example: BTC (Spark) to USDT (Tron)

{
  "sourceChain": "spark",
  "sourceAsset": "BTC",
  "destinationChain": "tron",
  "destinationAsset": "USDT",
  "amount": "100000",
  "recipientAddress": "TYourTronAddress...",
  "slippageBps": 50
}
Delivery to other chains (ethereum, arbitrum, optimism, polygon, tron, plasma) uses orchestration. The order progresses through swap, bridge, and delivery steps.

Deposit Flexibility and ZeroConf

Deposits do not need to match the quoted amountIn exactly. See Deposit Amount Flexibility for how over/underpayments are handled. For Bitcoin L1 deposits, ZeroConf enables instant credit without waiting for confirmations. When disabled or unavailable, Bitcoin L1 deposits wait for 3 on-chain confirmations. Exact-out orders always use confirmation-based processing.

USDB Sell Flows

For USDB sell flows (USDB to stablecoin), the quote returns a per-partner derived Spark address in depositAddress. This address is deterministic for a given partner and recipient combination. The sourceSparkAddress field is not required on submit for these flows.

Example: BTC (Lightning) to USDC

Lightning-source routes use a tiered platform fee: 0.20% (20 bps) when the destination is USDB, 0.40% (40 bps) for all other destinations. A Lightning quote returns a BOLT11 invoice in depositAddress and a lightningReceiveRequestId. Pay the invoice, then submit the receive request id. Quote response fields to pay:
  • depositAddress: BOLT11 invoice
  • amountIn: sats to pay
  • lightningReceiveRequestId: identifier used by submit
Submit request:
{
  "quoteId": "q_...",
  "lightningReceiveRequestId": "<id>"
}

Next Steps