Bitcoin Support - Relay

Relay Bitcoin Integration Guide

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

Action Parameter Input Description
Deposit to Bitcoin toChainId 8253038 Chain ID assigned to Bitcoin in Relay.
recipient User’s Bitcoin Address Valid Bitcoin address.
toCurrency bc1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmql8k8 Native BTC identifier.
Withdraw from Bitcoin chainId 8253038 Chain ID assigned to Bitcoin in Relay.
currency bc1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmql8k8 Native BTC identifier.

Bitcoin Currency

Token Currency Address Symbol Decimals
BTC bc1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmql8k8 BTC 8

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

Action Parameter Input Description
Deposit to Bitcoin recipient User’s Bitcoin Address Valid Bitcoin address.
destinationChainId 8253038 Chain ID assigned to Bitcoin in Relay.
destinationCurrency bc1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmql8k8 Native BTC identifier.
Withdraw from Bitcoin user User’s Bitcoin Address Valid Bitcoin address.
originChainId 8253038 Chain ID assigned to Bitcoin in Relay.
originCurrency bc1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmql8k8 Native BTC identifier.

Execution

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

For Bitcoin origin deposits, the request transitions to pending as soon as the deposit appears in the Bitcoin mempool — earlier than the equivalent transition on EVM origins. Block-confirmation policy still governs the move to submitted/success.

Example: Withdraw from Bitcoin to Base

Request:

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"\
  }'\

Response:

{
  "steps": [
    {
      "id": "deposit",
      "action": "Confirm transaction in your wallet",
      "description": "Depositing funds to the relayer to execute the swap for USDC",
      "kind": "transaction",
      "requestId": "0x90399ed9112ee951b6312fae28196e02384f6fd26c5d40a3d51bf2b0fbb1ae80",
      "depositAddress": "",
      "items": [
        {
          "status": "incomplete",
          "data": {
            "psbt": "70736274ff0100fdb4010200000007d5..."
          },
          "check": {
            "endpoint": "/intents/status/v3?requestId=0x90399ed9112ee951b6312fae28196e02384f6fd26c5d40a3d51bf2b0fbb1ae80",
            "method": "GET"
          }
        }
      ]
    }
  ],
  "fees": {
    "gas": {
      "currency": {
        "chainId": 8253038,
        "address": "bc1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmql8k8",
        "symbol": "BTC",
        "name": "Bitcoin",
        "decimals": 8,
        "metadata": {
          "logoURI": "https://assets.relay.link/icons/currencies/btc.png",
          "verified": true
        }
      },
      "amount": "3639",
      "amountFormatted": "0.00003639",
      "amountUsd": "2.654085",
      "minimumAmount": "3639"
    },
    "relayer": {
      "currency": {
        "chainId": 8253038,
        "address": "bc1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmql8k8",
        "symbol": "BTC",
        "name": "Bitcoin",
        "decimals": 8,
        "metadata": {
          "logoURI": "https://assets.relay.link/icons/currencies/btc.png",
          "verified": true
        }
      },
      "amount": "660",
      "amountFormatted": "0.0000066",
      "amountUsd": "0.481367",
      "minimumAmount": "660"
    }
  },
  "details": {
    "operation": "swap",
    "sender": "bc1q4vxn43l44h30nkluqfxd9eckf45vr2awz38lwa",
    "recipient": "0x03508bb71268bba25ecacc8f620e01866650532c",
    "currencyIn": {
      "currency": {
        "chainId": 8253038,
        "address": "bc1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmql8k8",
        "symbol": "BTC",
        "name": "Bitcoin",
        "decimals": 8,
        "metadata": {
          "logoURI": "https://assets.relay.link/icons/currencies/btc.png",
          "verified": true
        }
      },
      "amount": "100000",
      "amountFormatted": "0.001",
      "amountUsd": "72.934456",
      "minimumAmount": "100000"
    },
    "currencyOut": {
      "currency": {
        "chainId": 8453,
        "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
        "symbol": "USDC",
        "name": "USD Coin",
        "decimals": 6,
        "metadata": {
          "logoURI": "https://coin-images.coingecko.com/coins/images/6319/large/usdc.png?1696506694",
          "verified": true
        }
      },
      "amount": "72469395",
      "amountFormatted": "72.469395",
      "amountUsd": "72.446929",
      "minimumAmount": "71020007"
    },
    "timeEstimate": 4
  }
}

Example: Deposit to Bitcoin from Base

Request:

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"\
  }'\

Response:

{
  "steps": [
    {
      "id": "approve",
      "action": "Confirm transaction in your wallet",
      "description": "Sign an approval for USDC",
      "kind": "transaction",
      "requestId": "0xd24628d1b4707b389e0298ecf86733c9f524599a2e28bdb1458f27f58cc4d6ca",
      "items": [
        {
          "status": "incomplete",
          "data": {
            "from": "0x03508bb71268bba25ecacc8f620e01866650532c",
            "to": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
            "chainId": 8453
          }
        }
      ]
    },
    {
      "id": "deposit",
      "action": "Confirm transaction in your wallet",
      "description": "Depositing funds to the relayer to execute the swap for BTC",
      "kind": "transaction",
      "requestId": "0xd24628d1b4707b389e0298ecf86733c9f524599a2e28bdb1458f27f58cc4d6ca",
      "depositAddress": "",
      "items": [
        {
          "status": "incomplete",
          "data": {
            "from": "0x03508bb71268bba25ecacc8f620e01866650532c",
            "to": "0x4cd00e387622c35bddb9b4c962c136462338bc31",
            "chainId": 8453
          },
          "check": {
            "endpoint": "/intents/status/v3?requestId=0xd24628d1b4707b389e0298ecf86733c9f524599a2e28bdb1458f27f58cc4d6ca",
            "method": "GET"
          }
        }
      ]
    }
  ],
  "fees": {
    "gas": {
      "currency": {
        "chainId": 8453,
        "address": "0x0000000000000000000000000000000000000000",
        "symbol": "ETH",
        "name": "Ether",
        "decimals": 18,
        "metadata": {
          "logoURI": "https://assets.relay.link/icons/1/light.png",
          "verified": true
        }
      },
      "amount": "238331268682",
      "amountFormatted": "0.000000238331268682",
      "amountUsd": "0.000510",
      "minimumAmount": "238331268682"
    },
    "relayer": {
      "currency": {
        "chainId": 8453,
        "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
        "symbol": "USDC",
        "name": "USD Coin",
        "decimals": 6,
        "metadata": {
          "logoURI": "https://coin-images.coingecko.com/coins/images/6319/large/usdc.png?1696506694",
          "verified": true
        }
      },
      "amount": "678569",
      "amountFormatted": "0.678569",
      "amountUsd": "0.678359",
      "minimumAmount": "678569"
    }
  },
  "details": {
    "operation": "swap",
    "sender": "0x03508bb71268bba25ecacc8f620e01866650532c",
    "recipient": "bc1q4vxn43l44h30nkluqfxd9eckf45vr2awz38lwa",
    "currencyIn": {
      "currency": {
        "chainId": 8453,
        "address": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
        "symbol": "USDC",
        "name": "USD Coin",
        "decimals": 6,
        "metadata": {
          "logoURI": "https://coin-images.coingecko.com/coins/images/6319/large/usdc.png?1696506694",
          "verified": true
        }
      },
      "amount": "10000000",
      "amountFormatted": "10.0",
      "amountUsd": "9.996900",
      "minimumAmount": "10000000"
    },
    "currencyOut": {
      "currency": {
        "chainId": 8253038,
        "address": "bc1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqmql8k8",
        "symbol": "BTC",
        "name": "Bitcoin",
        "decimals": 8,
        "metadata": {
          "logoURI": "https://assets.relay.link/icons/currencies/btc.png",
          "verified": true
        }
      },
      "amount": "12759",
      "amountFormatted": "0.00012759",
      "amountUsd": "9.305707",
      "minimumAmount": "12504"
    },
    "timeEstimate": 158
  }
}

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 in the typical case. For high-value deposits — those whose origin amount exceeds a per-currency threshold — Relay waits for 2 block confirmations instead, to reduce the risk of a reorg invalidating the fill. Bitcoin’s block time averages ~10 minutes but varies significantly; blocks can arrive within minutes of each other or take 30-50 minutes. The timeEstimate field on the quote response reflects whichever rule applies — expect roughly one block of wait time for standard deposits and roughly two for high-value ones.

When polling for deposit address transactions, allow for at least 2-3 blocks worth of time (3-4 for high-value deposits) before considering a transaction stalled. You can monitor block times at mempool.space.

Manually Reindexing a Bitcoin Deposit

If a Bitcoin deposit is not picked up by automatic indexing, you can trigger a manual reindex by calling POST /transactions/index with chainId: 8253038 and the Bitcoin txHash. Relay verifies the transaction is included in a block before reindexing — calls for transactions that have not yet been confirmed in a block return 404. See the Transaction Indexing guide for the full request shape.

Quote Requirements for Deposit Addresses

When using useDepositAddress: true with Bitcoin as origin: