POST /v1/orchestration/offramp quotes an exact-in payout of BTC over Lightning to a Cash App username or a Lightning address. Funding the deposit address creates an order. Track it with the quote and status APIs.
amount is an integer string in the source asset’s smallest units. estimatedOut is sats. The destination is lightning:BTC, and delivery is variable, so the quote does not lock a dollar amount.
To receive dollars, the Cash App user opens the Bitcoin section and turns on “Receive Lightning as dollars”. Orchestra does not check that setting.
completed means the Lightning payment was delivered. It does not confirm a Cash App dollar credit, the dollar amount, or Cash App’s conversion fee. Other Lightning addresses receive BTC according to that wallet.Prerequisites
- An Orchestra account. Create one in the dashboard. Flashnet reviews new accounts before enabling API access.
- A server key (
fn_...) from API keys in the dashboard. Keep it on your backend. For browsers and apps, use a scoped client key (fnp_...); see Authentication.
Flow
1
Create the quote
Send 50 USDC on Solana to The response matches Quotes:
$username:Replace
SERVER_KEY with your fn_... key. Use a new X-Idempotency-Key for each operation and reuse it when retrying that same request. Amounts are integer strings in the asset’s smallest unit: "100000" is 0.001 BTC; "50000000" is 50 USDC on Base. Read each asset’s decimals from /routes.YOUR_SOURCE_CHAIN_REFUND_ADDRESS is an address on the source chain. $username is the Cash App recipient.quoteId, depositAddress, amountIn, estimatedOut, fees, and expiresAt. amountMode is exact_in. The price lasts 2 minutes.2
Fund the deposit address
Send
amountIn of the source asset to depositAddress before expiresAt. Include depositMemo when the quote returns one. Orchestra detects the deposit and creates the order. If detection misses it, submit the transaction.3
Track the order
Poll
GET /v1/orchestration/order?quoteId=QUOTE_ID with a server key until order is non-null, then follow Status. Client keys poll /status?quoteId=QUOTE_ID with the returned readToken. That token does not authorize an order-id SSE stream.Recipient
alice and $alice become [email protected]. The name, without $, is 1 to 20 letters or digits and must include a letter. Case is preserved. [email protected] and [email protected] are kept; the domain needs a dot. Invoices and URLs are rejected, including BOLT11, BOLT12, and https://cash.app/$alice.
The quote checks that syntax and does not look up the wallet. Orchestra fetches the LNURL pay request at delivery, after the sats amount is final. A missing account, a rejected callback, or an amount outside that wallet’s limits can fail after funding. Recovery uses refundAddress. See Status.
Request
refundAddress is required. Omit refundChain to refund on the source chain. refundChain may be bitcoin or lightning; a Lightning refund is an amountless BOLT11 invoice. TON, BNB, Tron, XRP, Litecoin, and Zcash refund on the source chain only.
The source asset must list lightning:BTC in route.to on GET /v2/orchestration/routes. Amount bounds are on Routes and limits. Client keys need orders:quote, and the call uses the quote rate limit.
Optional fields match /quote: refundChain, slippageBps, appFees, affiliateId, and affiliateIds. Unknown fields are rejected, including destinationChain, destinationAsset, amountMode, and deliveryMode. The same idempotency key and body return the original quote. A different body returns 409 idempotency_conflict.
Request and response fields: Create offramp quote.