Integrate xFunnel's x402 protocol bridge into your payment flow in three steps.
Bridge endpoint: https://xfunnel.polsia.app/api/v1/bridge
Forward your x402 (binary HTTP/S) payment request to the bridge endpoint.
xFunnel reads the Authorization: Pay header and attached payment payload,
routes to the target upstream, and captures the bridge fee before settlement.
curl -X POST https://xfunnel.polsia.app/api/v1/bridge \\
-H "Authorization: Pay recipient-address@chain" \\
-H "Content-Type: application/octet-stream" \\
-H "X-Request-Hash: sha256_abc123..." \\
-H "X-Bridge-Fee-Percent: 5" \\
--data-binary @payment_payload.bin
Required headers:
| Header | Value | Notes |
|---|---|---|
Authorization |
Pay 0x...@base |
Pay recipient in format address@chain. Chains: base, solana, polygon. |
Content-Type |
application/octet-stream |
x402 binary payload format. |
X-Request-Hash |
sha256_... |
SHA-256 hash of the binary payload for idempotency and deduplication. |
X-Bridge-Fee-Percent |
5 |
Optional. Default 5%. Set to override. Range: 0–20. |
X-Settlement-Wallet |
0x... |
Optional. Override the settlement wallet for fee routing. Defaults to bridge config. |
X-Forward-To |
https://... |
Optional. Override the upstream relay target. Defaults to signallayer-4.polsia.app. |
The bridge returns status codes that tell you how to proceed. Always inspect
X-Funnel-Fee and X-Funnel-Tx-Hash on successful responses.
| Status | Meaning | Action |
|---|---|---|
200 OK |
Payment verified and routed. Fee captured. | Read X-Funnel-Fee (fee collected, ETH on Base). Read X-Funnel-Tx-Hash for settlement reference. Proceed with your workflow. |
402 Payment Required |
Payment payload present but not verified by CDP. Fee not captured. | Inspect WWW-Authenticate header for challenge details. Retry after resolving the payment condition. |
503 Service Unavailable |
Upstream unreachable or circuit-breaking. Payment not routed. | Read Retry-After header. Implement exponential backoff in your retry logic. Check GET /api/v1/bridge/metrics for upstream health. |
400 Bad Request |
Malformed request — missing headers, invalid chain, bad payload. | Fix request format. Response body contains specific field error. |
200, the bridge fee is captured atomically with the transaction.
The fee is settled to the configured CDP_SETTLEMENT_WALLET on ETH/Base.
No fee is captured on 402, 503, or error responses — the payment is not confirmed.
X-Funnel-Fee: 0.005 ETH
X-Funnel-Tx-Hash: 0xabc123def456...
X-Funnel-Bridge-Version: 1.0.1
{
"status": "verified",
"upstream_tx_hash": "0xabc123def456...",
"fee_captured": "0.005",
"fee_asset": "ETH",
"fee_chain": "base",
"latency_ms": 340
}
The bridge exposes a TA (Technical Analysis) metadata endpoint that surfaces real-time provider health signals. Use this to implement intelligent routing: pick the upstream with the lowest latency, highest uptime, and best handshake reliability.
curl https://xfunnel.polsia.app/api/v1/metrics
{
"latency_ms": { "p50": 330, "p95": 1096, "p99": 2100, "avg": 414 },
"uptime_pct": 99.8,
"handshake_reliability": 0.98,
"assets_supported": ["ETH", "USDC", "DAI"],
"total_requests": 1874,
"total_fees_collected": "12.4500",
"volume_routed": "249.00",
"chain_breakdown": [
{ "chain": "base", "volume": "142.00", "tx_count": 891, "fees": "7.10" },
{ "chain": "solana", "volume": "67.00", "tx_count": 445, "fees": "3.35" },
{ "chain": "polygon", "volume": "40.00", "tx_count": 538, "fees": "2.00" }
],
"last_successful_at": "2026-06-16T03:10:44.000Z"
}
Key TA fields for routing:
| Field | Type | Routing Use |
|---|---|---|
latency_ms.avg |
number (ms) | Average round-trip. Lower = faster upstream. |
uptime_pct |
number (0–100) | Historical uptime. Drop below 95%? Failover. |
handshake_reliability |
number (0–1) | CDP verification success rate. Below 0.9? Circuit-break. |
assets_supported |
string[] | Accepted fee assets. ETH on Base is always supported. |
chain_breakdown |
object[] | Per-chain volume and fee splits. Use for load-aware routing. |
xFunnel charges a flat 5% bridge fee on all proxied transactions by default.
Fees are captured in ETH on Base and settled to the configured CDP_SETTLEMENT_WALLET.
| Parameter | Default | Override via Header | Range |
|---|---|---|---|
| Bridge fee percent | 5% | X-Bridge-Fee-Percent |
0 – 20 |
| Fee asset | ETH | — | Fixed: ETH on Base |
| Fee capture timing | On 200 | — | Atomic with payment verification |
| Settlement wallet | CDP_SETTLEMENT_WALLET env | X-Settlement-Wallet |
Any ETH address |
1.00 ETH · Bridge fee: 5% → 0.05 ETH captured at settlement. Settlement to CDP_SETTLEMENT_WALLET on Base.
End-to-end integration with xFunnel. Handles request signing, response parsing, TA-metadata-driven retry logic, and error handling.
const https = require('https');
const BASE = 'xfunnel.polsia.app';
const BRIDGE = `/api/v1/bridge`;
const METRICS = `/api/v1/metrics`;
// ── Fetch TA metadata ────────────────────────────────────────
async function getBridgeHealth() {
return new Promise((resolve, reject) => {
const opts = { hostname: BASE, path: METRICS, method: 'GET' };
let data = '';
const req = https.request(opts, res => {
res.on('data', chunk => data += chunk);
res.on('end', () => resolve(JSON.parse(data)));
});
req.on('error', reject);
req.end();
});
}
// ── Send x402 payment through xFunnel bridge ──────────────────
async function sendPayment({ recipient, chain, payload, feePercent = 5 }) {
return new Promise((resolve, reject) => {
const body = Buffer.from(payload); // binary payload
const headers = {
'Authorization': `Pay ${recipient}@${chain}`,
'Content-Type': 'application/octet-stream',
'Content-Length': body.length,
'X-Request-Hash': `sha256_${Buffer.from(body.slice(0, 32)).toString('hex').slice(0, 16)}`,
'X-Bridge-Fee-Percent': String(feePercent),
};
const req = https.request(
{ hostname: BASE, path: BRIDGE, method: 'POST', headers },
res => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => resolve({ status: res.statusCode, headers: res.headers, body: data }));
}
);
req.on('error', reject);
req.write(body);
req.end();
});
}
// ── Main: check health, then route ───────────────────────────
async function routePayment(opts) {
const health = await getBridgeHealth();
// Circuit-break if upstream is unhealthy
if (health.handshake_reliability < 0.9) {
throw new Error(`Upstream unhealthy (reliability=${health.handshake_reliability}). Retry later.`);
}
// Route with current avg latency logged
console.log(`[xFunnel] Routing to upstream (latency_avg=${health.latency_ms.avg}ms)`);
const result = await sendPayment(opts);
if (result.status === 200) {
console.log(`[xFunnel] Verified — fee ${result.headers['x-funnel-fee']} captured`);
return { ok: true, txHash: result.headers['x-funnel-tx-hash'], latencyMs: parseInt(result.body?.latency_ms || '0') };
}
if (result.status === 402) {
console.warn(`[xFunnel] Payment required — challenge: ${result.headers['www-authenticate']}`);
throw new Error('Payment not verified. Check WWW-Authenticate header.');
}
if (result.status === 503) {
const retryAfter = result.headers['retry-after'] || 5;
console.warn(`[xFunnel] Upstream unavailable. Retry after ${retryAfter}s.`);
throw new Error(`Upstream down. Retry after ${retryAfter}s.`);
}
throw new Error(`Unexpected response: ${result.status} — ${result.body}`);
}
// ── Usage ─────────────────────────────────────────────────────
routePayment({
recipient: '0xYourRecipientAddress',
chain: 'base',
payload: Buffer.from('your-binary-payment-data'),
feePercent: 5,
}).then(r => console.log('Success:', r))
.catch(err => console.error('Failed:', err.message));