Q402 Developer Docs
Everything you need to add gasless USDC payments to your product. One API. Any EVM chain. Zero gas for your users.
Overview
Q402 is a managed relay layer for stablecoin paymentsacross EVM chains. Your product sends USDC or USDT from a user's wallet without the user ever holding a native token — Q402's relayer submits the on-chain transaction and pays the gas.
User wallet Q402 API On-chain Your app
─────────── ──────── ──────── ────────
1. Sign EIP-712 ──▶ /api/payment/intent lock quote, planChain
/api/payment/activate scan TX, grant credits
2. Get API key ◀── (sandbox or live)
3. Call pay() ──▶ /api/relay ──▶ EIP-7702 Type-4 TX
verify · decrement USDC/USDT transfer
credits · cap checks user EOA ──▶ recipient
◀── webhook
HMAC-signed
relay.success
Dashboard ◀── delivery log · key rotation · gas tank balanceThree moving parts: an intent that locks the quote before payment, an activate step that scans the on-chain transfer and issues credits, and a relay that submits gasless payments for your users. Every relay can fire a signed webhook and is recorded for audit.
What is an API?
An API is just a URL your server calls. Like ordering food at a restaurant — you send a request ("here's a user's signed transaction"), Q402's server handles the work, and sends back a result ("done, txHash: 0xabc..."). No blockchain expertise needed on your end.
How It Works
Three actors. One transaction. Zero gas for your users.
Quick Start
Get your first gasless transaction running in under 5 minutes.
1 · Load the SDK
<script src="https://q402.quackai.ai/q402-sdk.js"></script>2 · One-line gasless payment (client-side)
// Initialize once with your API key + chain
const q402 = new Q402Client({
apiKey: "q402_live_YOUR_KEY",
chain: "bnb", // "bnb" | "avax" | "eth" | "xlayer" | "stable" | "mantle" | "injective"
});
// Note: when chain is "injective", only token: "USDT" is supported.
// Native USDC via Circle CCTP is announced for Q2 2026.
// Wallet popup appears — user signs, Q402 relays on-chain
// amount MUST be a human-readable decimal STRING (e.g. "50.00", "0.123456").
// Never pass a JS Number — IEEE-754 loses precision on 18-decimal tokens.
// Inputs exceeding the token's decimals or non-decimal strings throw.
const result = await q402.pay({
to: recipientAddress,
amount: "50.00",
token: "USDC",
});
// result → { success: true, txHash: "0xabc...", tokenAmount: "50", chain: "bnb" }
3 · Injective EVM (USDT-only)
Native USDC via Circle CCTP is announced for Q2 2026; until then, Injective uses USDT as the only payment token. The SDK gates this explicitly — passing token: "USDC" with chain: "injective" throws before any signature is requested, and the relay route enforces the same allowlist server-side.
const q402 = new Q402Client({
apiKey: "q402_live_YOUR_KEY",
chain: "injective",
});
const result = await q402.pay({
to: recipientAddress,
amount: "50.00",
token: "USDT", // required — USDC not yet supported on Injective
});4 · That's it
// Full result shape:
// {
// success: true,
// txHash: "0xdef456...",
// chain: "bnb",
// blockNumber: "38482910",
// tokenAmount: "50",
// token: "USDC",
// gasCostNative: 0.000021,
// method: "eip7702",
// }
console.log("Paid! TX:", result.txHash);Claude MCP
Q402 ships as a Model Context Protocol server so Claude Desktop, Claude Code, Cline, and any other MCP-compatible AI client can quote and (optionally) settle gasless USDC and USDT payments directly from a chat. The package is @quackai/q402-mcp on npm and bitgett/q402-mcp on GitHub.
1 · Install
# Claude Code CLI
claude mcp add q402 -- npx -y @quackai/q402-mcp
# Or paste this into claude_desktop_config.json:
# (macOS: ~/Library/Application Support/Claude/claude_desktop_config.json)
# (Windows: %APPDATA%\Claude\claude_desktop_config.json)
{
"mcpServers": {
"q402": {
"command": "npx",
"args": ["-y", "@quackai/q402-mcp"]
}
}
}2 · Tools exposed
| Tool | Auth | Purpose |
|---|---|---|
q402_quote | no auth | Compare gas cost + supported tokens across chains. Read-only. |
q402_balance | api key | Verify the configured key and report its plan tier (live vs sandbox). |
q402_pay | api key + signer + flag | Send a gasless payment. Sandbox by default — see below. |
3 · Sandbox vs live mode
By default q402_pay runs in sandbox — it returns a deterministic-looking fake transaction hash, no funds move, no gas-tank credit is consumed. To enable real on-chain transactions, all three environment variables must be set:
Q402_API_KEY=q402_live_... # live-tier key from /dashboard
Q402_PRIVATE_KEY=0xabc... # signer for the payer EOA
Q402_ENABLE_REAL_PAYMENTS=1 # explicit opt-inAnything missing → automatic sandbox fallback with a hint pointing at what to set. Two additional guards run regardless of mode: Q402_MAX_AMOUNT_PER_CALL (default $5) caps any single call, and Q402_ALLOWED_RECIPIENTS optionally restricts to an address allowlist.
q402_pay tool description tells the model to ALWAYS get explicit user confirmation of recipient + amount in chat before invoking. Combined with the sandbox default + cap + allowlist, that gives four layers of safety before any wei moves.Gas Pool
Q402 uses a gas pool model. You deposit native tokens (BNB, ETH, MNT, AVAX, INJ, OKB, or USDT0 on Stable) into a single Q402-managed Gas Tank address that is shared across all customers — your balance is tracked off-chain, per wallet, in our ledger. Every time a user transaction is relayed, the gas fee is automatically deducted from your per-wallet balance.
Send native tokens (BNB / ETH / MNT / AVAX / INJ / OKB / USDT0 on Stable) to the Q402 Gas Tank address shown in your dashboard. Your balance is tracked per wallet address. Note: the Gas Tank is a separate cold wallet from the hot relayer — never send funds to the relayer address directly.
Each relayed transaction deducts the actual gas cost in native tokens. Balances update in real time.
Withdrawals are processed manually by Q402 operations. Contact business@quackai.ai to request a refund. Funds always remain yours.
Authentication
All relay requests require your API key in the apiKey field of the request body. Connect your wallet to get a sandbox key (q402_test_*) immediately. Your live key (q402_live_*) is issued automatically once your on-chain payment is confirmed on /payment.
// POST /api/relay
{
"apiKey": "q402_live_YOUR_API_KEY",
"chain": "avax",
"token": "USDC",
...
}API Reference
Base URL: https://q402.quackai.ai/api
Submit a signed EIP-712 + EIP-7702 payload. Q402 verifies the signature and relays the transaction on-chain using your gas pool.
// Request body
{
"apiKey": "q402_live_YOUR_API_KEY",
"chain": "avax", // avax | bnb | eth | xlayer | stable | mantle | injective
"token": "USDC", // USDC | USDT
"from": "0xUserWallet...",
"to": "0xRecipient...",
"amount": "50000000", // atomic units (6 decimals = 50 USDC)
"deadline": 1751289600,
"witnessSig": "0xabc123...",
"authorization": { ... } // EIP-7702 authorization object
}
// Response 200
// All numeric amounts are returned as decimal strings to preserve
// 18-decimal token precision (IEEE-754 doubles lose precision at that scale).
{
"success": true,
"txHash": "0xdef456...",
"chain": "avax",
"blockNumber": "54540550",
"tokenAmount": "50",
"gasCostNative": "0.000021",
"method": "eip7702"
}Returns the relayer (facilitator) wallet address. Call this before constructing any TransferAuthorization — the facilitator field in the EIP-712 payload must match this value on all chains.
// GET /api/relay/info
{ "facilitator": "0xRelayerAddress..." }Chain Support
Same API, same SDK — regardless of which chain. Switch with one parameter.
| Chain | chain param | Chain ID | Gas token | Status | Avg gas/tx |
|---|---|---|---|---|---|
BNB Chain | bnb | 56 | BNB | Mainnet Live | ~$0.001 |
Ethereum | eth | 1 | ETH | Mainnet Live | ~$0.19 |
Avalanche | avax | 43114 | AVAX | Mainnet Live | ~$0.002 |
X Layer | xlayer | 196 | OKB | Mainnet Live | ~$0.001 |
Stable | stable | 988 | USDT0 ★ | Mainnet Live | ~$0.001 |
Mantle | mantle | 5000 | MNT | Mainnet Live | ~$0.001 |
Injective | injective | 1776 | INJ | Mainnet Live | ~$0.10 |
EIP-712 Signing
Q402 uses EIP-712 typed structured data signing — the same standard used by Uniswap, Compound, and major DeFi protocols. The user signs a human-readable message. No gas. No blockchain interaction.
Contract Addresses & Domain Names
// Implementation contract per chain
const CONTRACTS = {
avax: "0x96a8C74d95A35D0c14Ec60364c78ba6De99E9A4c", // Q402 Avalanche (chainId: 43114)
bnb: "0x6cF4aD62C208b6494a55a1494D497713ba013dFa", // Q402 BNB Chain (chainId: 56)
eth: "0x8E67a64989CFcb0C40556b13ea302709CCFD6AaD", // Q402 Ethereum (chainId: 1)
xlayer: "0x8D854436ab0426F5BC6Cc70865C90576AD523E73", // Q402 X Layer (chainId: 196)
stable: "0x2fb2B2D110b6c5664e701666B3741240242bf350", // Q402 Stable (chainId: 988)
mantle: "0x2fb2B2D110b6c5664e701666B3741240242bf350", // Q402 Mantle (chainId: 5000)
injective: "0x2fb2B2D110b6c5664e701666B3741240242bf350", // Q402 Injective (chainId: 1776)
};
// EIP-712 domain name — must match contract NAME constant exactly
const DOMAIN_NAMES = {
avax: "Q402 Avalanche",
bnb: "Q402 BNB Chain",
eth: "Q402 Ethereum",
xlayer: "Q402 X Layer",
stable: "Q402 Stable",
mantle: "Q402 Mantle",
injective: "Q402 Injective",
};
// verifyingContract:
// ALL chains → user's own EOA (address(this) under EIP-7702 delegation)Witness Type (unified across all chains)
// Every deployed Q402 impl contract uses the same EIP-712 typed struct:
const types = {
TransferAuthorization: [
{ name: "owner", type: "address" }, // token sender (user's EOA)
{ name: "facilitator", type: "address" }, // gas sponsor (Q402 relayer)
{ name: "token", type: "address" }, // ERC-20 contract (USDC / USDT / USDT0)
{ name: "recipient", type: "address" }, // payment destination
{ name: "amount", type: "uint256" }, // atomic units
{ name: "nonce", type: "uint256" }, // random uint256, replay protection
{ name: "deadline", type: "uint256" }, // unix timestamp
],
};
// verifyingContract is ALWAYS the user's own EOA — the contract computes its
// domain separator with address(this), which equals the user EOA under EIP-7702.Signing with ethers.js
// Fetch facilitator address first (required for all chains)
const { facilitator } = await fetch("https://q402.quackai.ai/api/relay/info").then(r => r.json());
const domain = {
name: DOMAIN_NAMES[chain],
version: "1",
chainId: chainId,
verifyingContract: userAddress, // user's own EOA — same for all chains under EIP-7702
};
const nonce = ethers.toBigInt(ethers.randomBytes(32)); // random uint256
const signature = await signer.signTypedData(domain, types, {
owner: userAddress,
facilitator,
token: tokenAddress,
recipient: recipientAddress,
amount: ethers.parseUnits("50", decimals), // 6 decimals on most chains; 18 only for Stable chain's USDT0
nonce,
deadline: BigInt(Math.floor(Date.now() / 1000) + 600),
});eip3009Nonce instead of authorization).ethers.parseUnits(amount, 18). The gas pool must also be funded in USDT0 — there is no separate native gas coin. (Note: USDT0 on Mantle uses the same OFT address but 6 decimals, matching the other chains.)Error Responses
Errors return a JSON body of the form { "error": string, "code"?: string }. The HTTP status conveys the failure class; error is a human-readable message and code (when present) is a stable machine-readable tag for programmatic handling.
Most failure modes today return only error (no code). The codes listed below are the stable tags currently emitted by the server.
FAQ
Ready to go gasless?
Pick a plan, send an on-chain payment, and your live API key is issued automatically. Sandbox key available for free to test first.