Skip to main content
Relay supports deposits to and withdrawals from Bitcoin across any supported chain. This guide covers the Bitcoin-specific parameters, PSBT signing, balance calculation, and API/SDK usage required for integration.

Required Information

Bitcoin transactions differ from EVM chains in several ways. The sections below highlight the Bitcoin-specific parameters and requirements for your integration.
Bitcoin addresses are case-sensitive.

SDK Properties

ActionParameterInputDescription
Deposit to BitcointoChainId8253038Chain ID assigned to Bitcoin in Relay.
recipientUser’s Bitcoin AddressValid Bitcoin address.
toCurrencybc1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmql8k8Native BTC identifier.
Withdraw from BitcoinchainId8253038Chain ID assigned to Bitcoin in Relay.
currencybc1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmql8k8Native BTC identifier.

Bitcoin Currency

TokenCurrency AddressSymbolDecimals
BTCbc1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmql8k8BTC8

PSBT Signing

Bitcoin transactions use Partially Signed Bitcoin Transactions (PSBT) for signing. When withdrawing from Bitcoin, the quote response returns a PSBT instead of standard EVM calldata. The Bitcoin wallet adapter handles PSBT parsing, finalization, and broadcasting. Provide a signPsbt callback that signs the PSBT and returns the signed result in base64 format.

UTXOs and Bitcoin Balance

Unlike EVM chains that track account balances directly, Bitcoin uses a UTXO (Unspent Transaction Output) model. Each address balance equals the sum of unspent outputs it has received minus outputs it has spent. To calculate a Bitcoin address balance, query the mempool.space API and compute the difference between funded and spent transaction outputs:
async function getBitcoinBalance(address: string) {
	const response = await fetch(
		`https://mempool.space/api/address/${address}`
	);
	const data = await response.json();

	const fundedTxo = data.chain_stats.funded_txo_sum;
	const spentTxo = data.chain_stats.spent_txo_sum;
	const pendingSpent = data.mempool_stats.spent_txo_sum;

	// Balance in satoshis
	const balance =
		BigInt(fundedTxo) - BigInt(spentTxo) - BigInt(pendingSpent);

	return {
		balance, // Confirmed balance in satoshis
		pendingBalance: BigInt(pendingSpent), // Pending outgoing
	};
}
Balance values are returned in satoshis (1 BTC = 100,000,000 satoshis).

API

Params

ActionParameterInputDescription
Deposit to BitcoinrecipientUser’s Bitcoin AddressValid Bitcoin address.
destinationChainId8253038Chain ID assigned to Bitcoin in Relay.
destinationCurrencybc1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmql8k8Native BTC identifier.
Withdraw from BitcoinuserUser’s Bitcoin AddressValid Bitcoin address.
originChainId8253038Chain ID assigned to Bitcoin in Relay.
originCurrencybc1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmql8k8Native BTC identifier.

Execution

Bitcoin uses the standard Relay API flow. Review the execution steps documentation, then use the Get Quote endpoint.

Example: Withdraw from Bitcoin to Base

curl -X POST "https://api.relay.link/quote/v2" \
  -H "Content-Type: application/json" \
  -d '{
    "user": "bc1q4vxn43l44h30nkluqfxd9eckf45vr2awz38lwa",
    "originChainId": 8253038,
    "originCurrency": "bc1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmql8k8",
    "destinationChainId": 8453,
    "destinationCurrency": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
    "recipient": "0x03508bb71268bba25ecacc8f620e01866650532c",
    "tradeType": "EXACT_INPUT",
    "amount": "100000"
  }'

Example: Deposit to Bitcoin from Base

curl -X POST "https://api.relay.link/quote/v2" \
  -H "Content-Type: application/json" \
  -d '{
    "user": "0x03508bb71268bba25ecacc8f620e01866650532c",
    "originChainId": 8453,
    "originCurrency": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
    "destinationChainId": 8253038,
    "destinationCurrency": "bc1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmql8k8",
    "recipient": "bc1q4vxn43l44h30nkluqfxd9eckf45vr2awz38lwa",
    "tradeType": "EXACT_INPUT",
    "amount": "10000000"
  }'
Amounts are specified in the smallest unit of the currency. For BTC, this is satoshis (100000 satoshis = 0.001 BTC). For USDC, this is 6 decimal places (10000000 = 10 USDC).

SDK

To use the SDK with Bitcoin, install and configure the Bitcoin wallet adapter. The adapter handles PSBT signing and transaction broadcasting.
npm install @relayprotocol/relay-bitcoin-wallet-adapter
For implementation details and code samples, see the Adapters documentation.

Deposit Addresses (Optional)

Relay also supports the deposit address flow, which allows bridging without wallet connection or PSBT signing. When using deposit addresses, there are additional considerations:

Block Confirmations

When using deposit addresses, Relay waits for 1 block confirmation before processing. Bitcoin’s block time averages ~10 minutes but varies significantly. blocks can arrive within minutes of each other or take 30-50 minutes.
When polling for deposit address transactions, allow for at least 2-3 blocks worth of time before considering a transaction stalled. You can monitor block times at mempool.space.

Quote Requirements for Deposit Addresses

When using useDepositAddress: true with Bitcoin as origin:
  • The user address must be a valid Bitcoin address
  • The user address balance must exceed the quoted amount (otherwise returns INSUFFICIENT_FUNDS)
  • For indicative quotes, use a known high-balance address (“whale address”). The actual deposit can originate from any address.
curl -X POST "https://api.relay.link/quote/v2" \
  -H "Content-Type: application/json" \
  -d '{
    "user": "bc1q4vxn43l44h30nkluqfxd9eckf45vr2awz38lwa",
    "originChainId": 8253038,
    "originCurrency": "bc1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmql8k8",
    "destinationChainId": 8453,
    "destinationCurrency": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
    "recipient": "0x03508bb71268bba25ecacc8f620e01866650532c",
    "tradeType": "EXACT_INPUT",
    "amount": "100000",
    "useDepositAddress": true,
    "refundTo": "bc1q4vxn43l44h30nkluqfxd9eckf45vr2awz38lwa"
  }'