Frequently Asked Questions
Quick answers to common questions about x402 escrow payments.
Costs & Fees
How much gas does this cost?
Users pay $0 in gas. The system uses ERC-3009 transferWithAuthorization signatures, which are completely gasless for users.
| Who | Gas Cost |
|---|
| User (Payer) | $0 - only signs messages |
| API Provider | $0 - facilitator covers everything |
| Facilitator | ~$0.01-0.05 per session (covered by facilitator) |
This is one of the main benefits of x402 escrow - users never need ETH for gas.
Is there a fee on top of payments?
All fees are currently sponsored by Agentokratia. We cover gas costs and charge no platform fee. Any future fee changes will be announced well in advance.
What’s the minimum I can charge per request?
Technically 0.0001USDC(1/100thofacent).However,werecommend0.001+ for practical pricing.
Tokens & Networks
Can I use this with other tokens besides USDC?
Currently, USDC only. USDC was chosen because:
- Stable value (no price volatility)
- Widely held and understood
- Native support for gasless transfers (ERC-3009)
- Available on Base with high liquidity
Other stablecoins may be supported in the future.
Which networks are supported?
| Network | Chain ID | Status |
|---|
| Base Sepolia | 84532 | Live (Testnet) |
| Base Mainnet | 8453 | Coming Soon |
We chose Base for its low gas costs and Coinbase ecosystem integration.
Can I use this on Ethereum mainnet?
Not currently. Ethereum mainnet gas costs would make small payments impractical. Base offers the same security with ~100x lower fees.
Security & Reliability
What if the facilitator goes down?
Your funds are safe. User deposits are held in the on-chain escrow smart contract, not by the facilitator.
If the facilitator is unavailable:
- No new sessions can be created
- Existing session charges won’t be captured
- Users can call
reclaim() directly on the contract after authorizationExpiry
- API providers can implement fallback logic (serve for free, use cached responses, etc.)
// Server-side fallback during outage
x402.onError(async (ctx, error) => {
if (error.status === 503) {
// Facilitator down - decide how to handle
console.log('Facilitator unavailable, serving request for free');
return { proceed: true }; // Continue without payment
}
});
What if I accidentally double-charge a user?
Impossible by design. Each request includes a unique requestId (UUID). The facilitator enforces idempotency - the same requestId can only be charged once.
// These two calls charge only once
await escrowFetch(url, { requestId: 'request-123' });
await escrowFetch(url, { requestId: 'request-123' }); // No additional charge
Can users dispute or chargeback payments?
No chargebacks. Unlike credit cards, cryptocurrency payments are final. The session token serves as cryptographic proof that the user authorized the payment.
This is actually a benefit for API providers - no chargeback fraud risk.
Is the escrow contract audited?
The escrow contract is built on Base’s Commerce Payments Protocol, a production-grade payment infrastructure:
- Open source: View the smart contract on GitHub
- ERC-3009: Gasless approvals via
transferWithAuthorization
- Time-locked: Explicit authorization windows with enforced expiry
- Battle-tested: Based on patterns used in traditional payment processing
Formal audit documentation will be published before mainnet launch.
Sessions & Payments
How long do sessions last?
Default is 1 hour, configurable up to 24 hours:
const { fetch: escrowFetch } = createEscrowFetch(walletClient, {
sessionDuration: 7200, // 2 hours
});
After expiry, users can reclaim unused funds.
What happens to unused funds?
Users get 100% of unused funds back. After authorizationExpiry:
- User (or anyone) can call
reclaim() on the contract
- Remaining balance returns to user’s wallet
- Facilitator captures any pending charges first
Can I refund a user?
There are two types of “getting money back”:
| Type | What it is | How |
|---|
| Reclaim | Unused balance (never captured) | User calls reclaim() on contract |
| Refund | Already-captured funds | 🔜 Coming soon via API |
Currently:
- Users automatically reclaim unused session balance via contract
- Refund API coming soon
See Refund vs Reclaim for details.
What if a user’s session runs out of balance mid-request?
The request will fail with insufficient_balance. Handle it gracefully:
const response = await escrowFetch(url);
if (!response.ok) {
const { reason } = await response.json();
if (reason === 'insufficient_balance') {
// Prompt user to create new session with more funds
await escrowFetch(url, { session: 'new' });
}
}
Integration
Do I need an API key?
Servers: Yes, to authenticate with the facilitator for verification and settlement.
Clients: No, clients just need a wallet to sign sessions.
Get your API key at facilitator.agentokratia.com.
Does this work with React/Next.js/Vue/etc?
Yes! The SDK is framework-agnostic. It works with any JavaScript environment that has:
- A wallet connection (viem WalletClient)
- Fetch API (or polyfill)
See our React example for integration patterns.
Can I use this server-side (Node.js)?
For protecting APIs: Yes, the server SDK works in any Node.js environment.
For making payments as a client: You’d need a wallet with a private key. Not recommended for servers due to security implications of storing private keys.
How do I test without real money?
Use Base Sepolia testnet:
- Get your API key from facilitator.agentokratia.com (same key works on all networks)
- Get testnet USDC from a faucet
- Configure your app for Sepolia:
import { baseSepolia } from 'viem/chains';
const walletClient = createWalletClient({
chain: baseSepolia,
transport: http(),
});
Troubleshooting
Why am I getting “User rejected” errors?
The user clicked “Reject” in their wallet’s signature prompt. This is expected behavior when users cancel. Handle it gracefully:
try {
await escrowFetch(url);
} catch (err) {
if (err.message?.includes('User rejected')) {
showToast('Transaction cancelled');
return;
}
throw err;
}
Check that your system clock is accurate. Session expiry is based on Unix timestamps. If your clock is significantly off, sessions may appear expired.
How do I debug payment issues?
Enable logging with hooks:
const { fetch: escrowFetch, x402 } = createEscrowFetch(walletClient);
x402.onBeforePaymentCreation(async (ctx) => {
console.log('[x402] Payment required:', ctx.paymentRequirements);
});
x402.onAfterPaymentCreation(async (ctx) => {
console.log('[x402] Payment created:', ctx.paymentPayload);
});
Still Have Questions?