coal
coal

Multi-Token Payments

Multi-Token lets your customers pay with a token they already hold while your merchant account settles in the configured settlement token for that account. In Coal today, that is typically USDC unless a custom settlement token has been configured.

Powered by Li.Fi, Coal can quote and route a cross-chain swap or same-chain swap between the customer token and the configured settlement token.

Multi-Token is currently in beta. Enable it under Console → Settings → Multi-Token.


How It Works

  1. The customer selects an input token in the Coal checkout.
  2. Coal fetches a Li.Fi quote for the configured settlement amount.
  3. The customer reviews the quote, including estimated gas and slippage.
  4. The customer signs the swap transaction in their wallet.
  5. Li.Fi routes the swap across DEXes or bridges as needed.
  6. Your merchant wallet receives the configured settlement token.

Supported Input Tokens

TokenNetworks
ETHEthereum, Arbitrum, Optimism, Base
USDCEthereum, Arbitrum, Optimism, Base, Polygon
USDTEthereum, Arbitrum, Polygon, BNB Chain
MATICPolygon
BNBBNB Chain
DAIEthereum, Arbitrum, Polygon
WBTCEthereum, Arbitrum
ARBArbitrum
OPOptimism

Support for additional tokens depends on Li.Fi liquidity routing. The checkout UI only shows tokens that can realistically route to the configured settlement token.


The Quotes API

GET /api/lifi/quote

bash
1curl "https://api.usecoal.xyz/api/lifi/quote?fromToken=ETH&fromChain=ethereum&toAmount=49.99" \
2 -H "x-api-key: coal_live_..."

Response:

json
1{
2 "fromToken": "ETH",
3 "fromChain": "ethereum",
4 "fromAmount": "0.0281",
5 "toToken": "USDC",
6 "toAmount": "49.99",
7 "slippage": 0.005,
8 "estimatedGasUsd": "1.83",
9 "estimatedDurationSeconds": 45,
10 "route": {
11 "steps": [
12 {
13 "type": "swap",
14 "protocol": "Uniswap V3",
15 "fromToken": "ETH",
16 "toToken": "USDC"
17 }
18 ]
19 },
20 "expiresAt": "2026-03-22T12:01:30.000Z"
21}

Quotes expire after 90 seconds. Re-fetch if the customer takes longer to confirm.


Using the Quote in Your Code

typescript
1export interface LifiQuote {
2 fromToken: string;
3 fromChain: string;
4 fromAmount: string;
5 toToken: string;
6 toAmount: string;
7 slippage: number;
8 estimatedGasUsd: string;
9 estimatedDurationSeconds: number;
10 expiresAt: string;
11}
12
13export async function getLifiQuote(
14 fromToken: string,
15 fromChain: string,
16 toAmount: string
17): Promise<LifiQuote> {
18 const url = new URL('https://api.usecoal.xyz/api/lifi/quote');
19 url.searchParams.set('fromToken', fromToken);
20 url.searchParams.set('fromChain', fromChain);
21 url.searchParams.set('toAmount', toAmount);
22
23 const res = await fetch(url.toString(), {
24 headers: { 'x-api-key': process.env.COAL_API_KEY! },
25 next: { revalidate: 0 },
26 });
27
28 if (!res.ok) {
29 throw new Error(`Li.Fi quote failed: ${res.status}`);
30 }
31
32 return res.json();
33}
tsx
1import { getLifiQuote } from '@/lib/lifi';
2
3export default async function CheckoutPage() {
4 const quote = await getLifiQuote('ETH', 'ethereum', '49.99');
5
6 return (
7 <div>
8 <p>Pay with ETH: {quote.fromAmount} ETH</p>
9 <p>Estimated gas: ${quote.estimatedGasUsd}</p>
10 <p>You receive: {quote.toAmount} settlement-token units</p>
11 </div>
12 );
13}

Slippage

Default slippage tolerance is 0.5% (0.005). This means Li.Fi may deliver up to 0.5% less than the quoted settlement amount. Coal's verification accounts for this tolerance, so a payment that lands within the slippage band is still marked confirmed.

To adjust slippage for a specific session:

bash
1curl -X POST https://api.usecoal.xyz/api/checkouts \
2 -H "Content-Type: application/json" \
3 -H "x-api-key: coal_live_..." \
4 -d '{
5 "amount": 100.00,
6 "description": "Annual Subscription",
7 "multiToken": {
8 "enabled": true,
9 "slippage": 0.01
10 }
11 }'

Allowed range: 0.001 (0.1%) to 0.05 (5%).


Gas

Gas is paid by the customer in their source chain's native token (for example ETH for Ethereum swaps). The Li.Fi quote includes estimatedGasUsd so you can display the all-in cost before the customer signs.

Gas is never deducted from the settlement amount your merchant receives.


Enabling Multi-Token

  1. Open Console → Settings → Multi-Token.
  2. Toggle Enable Multi-Token Payments.
  3. Optionally set default slippage tolerance.
  4. Click Save.

Once enabled, the Coal checkout page automatically displays a token selector to customers.

To enable programmatically on a per-session basis:

bash
1curl -X POST https://api.usecoal.xyz/api/checkouts \
2 -H "Content-Type: application/json" \
3 -H "x-api-key: coal_live_..." \
4 -d '{
5 "amount": 25.00,
6 "description": "Pro Plan",
7 "multiToken": {
8 "enabled": true
9 }
10 }'

Webhook Payload

When a Multi-Token payment confirms, the webhook includes the original input token details alongside the settled amount:

json
1{
2 "event": "checkout.confirmed",
3 "id": "evt_clx7k2p3q0000abc12345",
4 "timestamp": "2026-03-22T12:00:00.000Z",
5 "data": {
6 "sessionId": "clx7k2p3q0000abc12345",
7 "merchantId": "clx1mer0h0000xyz98765",
8 "amount": "49.99",
9 "currency": "USDC",
10 "status": "confirmed",
11 "txHash": "0xabc123...",
12 "multiToken": {
13 "inputToken": "USDC",
14 "inputChain": "arbitrum",
15 "inputAmount": "50.24",
16 "lifiTxHash": "0xdef456...",
17 "route": "Uniswap V3"
18 },
19 "description": "Pro Plan",
20 "metadata": {}
21 }
22}

Limitations

  • Maximum single-payment value: 10,000 USD equivalent.
  • Some token/chain combinations may return no quote if liquidity is insufficient. Fall back to the configured settlement-token flow in that case.
  • Cross-chain swaps can take up to 3 minutes to settle. Sessions have a 35-minute expiry to accommodate this.
  • Multi-Token is not compatible with pricingModel: "per_call" paywalls.