Skip to main content
This guide walks you through the complete payment lifecycle using Chainrails, from generating a payment intent, funding it, to confirming its success using the APIs.

Step 1 — Request a Quote

Before creating a payment intent, you need to request for quotes to help the user understand the costs for the multiple cross-chain routes available.
  • We often recommend using the multi-source quote endpoint to get quotes from multiple source chains for a given destination chain. This fetches the best quotes for multiple source chains, providing more options for the user. See Multi-Source Quotes for more details.
But you can also request a single quote for a specific source chain, bridge option etc. if you decide to. See the Api Reference for all available quote endpoints.
curl --request GET \
  --url "https://api.chainrails.io/api/v1/quotes/multi-source?destinationChain=ARBITRUM_TESTNET&amount=1.5&tokenOut=0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d" \
  --header "Authorization: Bearer YOUR_API_KEY"

Step 2 — Curate a Payment Intent

Once the user chooses a route (from the generated quotes), prepare a payment intent payload that defines:
  • The selected route/chain
  • The total amount to be sent
  • The destination chain and recipient
This object will be used to initialize the intent on Chainrails.
Payment Intent
{
  "sender": "0xdA3ECb2E5362295E2b802669dD47127A61d9Ce54",
  "amount": "1000000",
  "tokenIn": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
  "source_chain": "BASE_TESTNET",
  "destination_chain": "ARBITRUM_TESTNET",
  "recipient": "0xb79541Be080a59fdcE6C0b43219ba56c725eC65e",
  "refund_address": "0xb79541Be080a59fdcE6C0b43219ba56c725eC65e",
  "metadata": {
    "description": "Cross-chain USDC transfer",
    "reason": "sales invoice #1234",
  }
}

Step 3 — Create the Payment Intent

Call the POST /api/v1/intents endpoint with the curated payment intent.
curl --request POST \
  --url https://api.chainrails.io/api/v1/intents \
  --header "Authorization: Bearer YOUR_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "sender": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
    "amount": "1000000",
    "tokenIn": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
    "source_chain": "BASE_TESTNET",
    "destination_chain": "ARBITRUM_TESTNET",
    "recipient": "0xb79541Be080a59fdcE6C0b43219ba56c725eC65e",
    "refund_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
    "metadata": {
      "orderId": "12345"
    }
  }'

Sample Response

{
  "id": 2,
  "client_id": "e1ee3675-cb26-4a76-8206-a84f86e85862",
  "sender": "0xdA3ECb2E5362295E2b802669dD47127A61d9Ce54",
  "initialAmount": "1000000",
  "fees": "10500",
  "totalAmount": "1010500",
  "tokenIn": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
  "tokenOut": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d",
  "intent_address": "0x4E60e01263E750eD9D087157e19D2480Fd86A900",
  "source_chain": "BASE_TESTNET",
  "destination_chain": "ARBITRUM_TESTNET",
  "recipient": "0xb79541Be080a59fdcE6C0b43219ba56c725eC65e",
  "refund_address": "0xb79541Be080a59fdcE6C0b43219ba56c725eC65e",
  "relayer": "",
  "coordinator": "0x989f47053F188778575113DcF39dB8960Fc450e2",
  "bridger": "0xa1c943058a631D5506eb7d96036eAbF6968e2338",
  "bridgeExtraData": "0x00000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000003e8000000000000000000000000000000000000000000000000000000000000000300000000000000000000000075faf114eafb1bdbe2f0316df893fd58ce46aa4d",
  "intent_nonce": 4267684716645197,
  "intent_status": "PENDING",
  "tx_hash": null,
  "needs_relay": false,
  "expires_at": "2025-11-11T02:31:23.000Z",
  "metadata": {
    "priority": "normal",
    "description": "Cross-chain USDC transfer"
  },
  "created_at": "2025-11-11T01:31:23.390Z",
  "updated_at": "2025-11-11T01:31:23.390Z"
}

Step 4 — User Funds the Payment Intent

Display the intent deposit address to the user on your payment screen. The user should send the exact totalAmount from their wallet on the selected source chain. Once the funds are detected on-chain, the Chainrails protocol takes over.

Step 5 - Automated execution

After the deposit is confirmed, Chainrails:
  1. Starts the intent automatically
  2. Prefills the transaction on the destination chain for the end user
  3. Refunds the relayer, who provided the liquidity to prefill the cross-chain execution, or
  4. Refunds the user if the intent expired without initiating.
At this stage, you do not need to take any further action — the entire bridging and execution process is handled by the protocol. NB: You can however trigger the intent processing flow manually, if the indexer goes down for any reason or missed a transaction, using the GET /api/v1/intents/{intent_address}/trigger-processing endpoint.

Step 6 - Track Status via Webhooks

You can subscribe to webhooks to receive real-time updates on the intent’s lifecycle, including:
  • intent_funded
  • intent_initiated
  • intent_completed
  • intent_refunded
You can find setup instructions in the Webhook Section

Additional Tips

  1. Intent addresses are like one-off account numbers, they can’t be reused, so a new one is generated for every intent.
  2. If the user under-funds the intent, the transaction will fail to start, and the user can either top up the balance of the intent address, or a refund will be processed after intent expiration.
  3. If the user over-pays an intent, the excess is refunded on intent initiation.
  4. API keys have a rate limit of 250 rps, contact the team if you need modifications to this.

Github Example

Check out our Github demo repository for copy-paste code examples.