> ## Documentation Index
> Fetch the complete documentation index at: https://docs.flashnet.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# BTC to Stablecoin

> Sell BTC or USDB for USDC, USDT, ETH, SOL, and other assets on any supported chain via Orchestra.

This flow starts with a BTC (or USDB) deposit and ends with USDC, PathUSD, USDT, ETH, SOL, BNB, DAI, TRX, WBTC, cbBTC, or USDC.e delivered to any supported chain.

If you want a reusable Bitcoin address that runs this flow automatically on each deposit, use [reusable addresses](/products/orchestration/reusable-addresses#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, BNB, DAI, TRX, WBTC, cbBTC, or USDC.e 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](/products/orchestration/stablecoin-to-btc#example-usdc-to-btc-lightning-exact-out).

<Accordion title="Supported routes">
  - `BTC (spark) -> USDC/USDT/ETH (ethereum|arbitrum|optimism|base), USDC/USDC.e (polygon), USDC (solana|tempo|monad), PathUSD (tempo), SOL (solana), BNB/USDT (bsc), DAI/WBTC (ethereum), TRX/USDT (tron), USDT (plasma), cbBTC (base|solana|monad)`
  - `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](/products/orchestration/stablecoin-to-btc#example-usdc-to-btc-lightning-exact-out).

  Affiliate fee settlement (`appFees`, `affiliateId`, or `affiliateIds`) requires `amountMode = exact_in`.
</Accordion>

## 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`, a ZeroConf offer is pending (`order.zeroconfOffer`). Accept or decline via the zeroconf endpoints. See [ZeroConf](/products/orchestration/zeroconf).

Quotes expire 2 minutes after creation.

## Example: BTC (Spark) to USDC (Base)

```ts theme={null}
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:

```json theme={null}
{
  "sourceChain": "bitcoin",
  "sourceAsset": "BTC",
  "destinationChain": "solana",
  "destinationAsset": "USDC",
  "amount": "250000",
  "recipientAddress": "So1...",
  "slippageBps": 50,
  "zeroconfEnabled": true
}
```

Submit request:

```json theme={null}
{
  "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:

```json theme={null}
{
  "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 refunds automatically to `paymentIntent.refundAddress`. The relevant `errorCode` will be `exact_out_insufficient_input`, `exact_out_input_above_max`, or `exact_out_target_not_met`. See [Error codes](/products/orchestration/api/error-codes#order-lifecycle-error-codes).

## Example: BTC (Spark) to USDC (Solana) with affiliate fees

```json theme={null}
{
  "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

```json theme={null}
{
  "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](/products/orchestration/api/quotes-and-orders#post-v1orchestrationquote) for the full affiliate fee model, response fields, and settlement behavior.

## Example: BTC (Spark) to USDT (Tron)

```json theme={null}
{
  "sourceChain": "spark",
  "sourceAsset": "BTC",
  "destinationChain": "tron",
  "destinationAsset": "USDT",
  "amount": "100000",
  "recipientAddress": "TYourTronAddress...",
  "slippageBps": 50
}
```

Delivery to other chains (ethereum, arbitrum, optimism, polygon, bsc, tempo, tron, plasma, monad) uses Orchestra routing. The order progresses through swap, bridge, and delivery steps.

## How do deposit flexibility and ZeroConf work?

Deposits do not need to match the quoted `amountIn` exactly. See [Deposit Amount Flexibility](/products/orchestration/order-lifecycle#what-happens-if-the-deposit-amount-differs-from-the-quote) for how over/underpayments are handled.

For Bitcoin L1 deposits, [ZeroConf](/products/orchestration/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 custom pricing. USDB destinations get the lowest rates.

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:

```json theme={null}
{
  "quoteId": "q_...",
  "lightningReceiveRequestId": "<id>"
}
```

## Next steps

* [API Reference](/products/orchestration/api/overview)
* [Webhooks](/products/orchestration/webhooks)
