🤖Agent SDK
@x402/agent
TypeScript SDK for AI agents that consume paid APIs. Drop-in fetch replacement with automatic x402 payment handling.
Installation
bash
npm install @x402/agent
# or
pnpm add @x402/agent
# or
yarn add @x402/agentConfiguration
Create an agent client with your Gateway URL and API key:
typescript
import { createAgentClient, AgentClientConfig } from '@x402/agent';
const config: AgentClientConfig = {
// Required: Gateway API base URL
gatewayBaseUrl: 'https://xfour.xyz/api/gateway',
// Required: Your agent API key
apiKey: process.env.X402_AGENT_KEY!,
// Optional: Custom fetch implementation (default: global fetch)
fetchImpl: customFetch,
// Optional: Header name for payment proof
// (default: 'X-MOCK-PAID-INVOICE')
proofHeaderName: 'X-MOCK-PAID-INVOICE',
};
const client = createAgentClient(config);Configuration Options
| Option | Type | Required | Description |
|---|---|---|---|
| gatewayBaseUrl | string | Yes | Base URL of the x402 Gateway |
| apiKey | string | Yes | Your agent API key |
| fetchImpl | typeof fetch | No | Custom fetch implementation |
| proofHeaderName | string | No | Header name for payment proof |
fetchWithX402
The main method for making requests. Works exactly like fetch, but automatically handles 402 Payment Required responses.
typescript
const response = await client.fetchWithX402(
'https://api.example.com/ai/complete',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ prompt: 'Hello world' }),
}
);
console.log('Status:', response.status);
console.log('Body:', await response.json());How It Works
- 1. Initial Request — Makes your request normally
- 2. Non-402 Response — If not 402, returns immediately
- 3. 402 Response — Extracts X-402-* headers
- 4. Quote — Calls Gateway /quote for authorization
- 5. Payment — If allowed, calls /pay to execute
- 6. Retry — Retries original request with proof header
Error Handling
The SDK provides typed error classes for payment failures:
PaymentDeniedError
Thrown when the Gateway denies a payment quote (policy violation, insufficient balance, etc.).
typescript
import { PaymentDeniedError } from '@x402/agent';
try {
await client.fetchWithX402(url);
} catch (err) {
if (err instanceof PaymentDeniedError) {
console.log('Denied reason:', err.reason);
// Possible reasons:
// - "AGENT_DAILY_LIMIT"
// - "INSUFFICIENT_BALANCE"
// - "PROVIDER_NOT_ALLOWED"
// - "AMOUNT_EXCEEDS_LIMIT"
}
}PaymentFailedError
Thrown when a payment execution fails (network error, transaction failure, etc.).
typescript
import { PaymentFailedError } from '@x402/agent';
try {
await client.fetchWithX402(url);
} catch (err) {
if (err instanceof PaymentFailedError) {
console.log('Error code:', err.code);
console.log('Details:', err.details);
}
}Complete Error Handling Example
typescript
import {
createAgentClient,
PaymentDeniedError,
PaymentFailedError
} from '@x402/agent';
async function makeRequest() {
const client = createAgentClient({
gatewayBaseUrl: 'https://xfour.xyz/api/gateway',
apiKey: process.env.X402_AGENT_KEY!,
});
try {
const res = await client.fetchWithX402(
'https://api.example.com/ai/complete',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ prompt: 'Hello' }),
}
);
return await res.json();
} catch (err) {
if (err instanceof PaymentDeniedError) {
// Handle policy denial
console.error('Payment denied:', err.reason);
// Maybe notify admin, show upgrade prompt, etc.
} else if (err instanceof PaymentFailedError) {
// Handle execution failure
console.error('Payment failed:', err.message);
// Maybe retry later, alert monitoring, etc.
} else {
// Other errors (network, etc.)
throw err;
}
}
}Examples
Basic AI Completion
typescript
const response = await client.fetchWithX402(
'https://api.openrouter.ai/v1/complete',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: 'gpt-4',
messages: [{ role: 'user', content: 'Hello!' }],
}),
}
);
const data = await response.json();
console.log(data.choices[0].message.content);Streaming Response
typescript
const response = await client.fetchWithX402(
'https://api.example.com/stream',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ prompt: 'Write a poem' }),
}
);
const reader = response.body?.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader!.read();
if (done) break;
process.stdout.write(decoder.decode(value));
}Multiple Requests in Parallel
typescript
const [result1, result2, result3] = await Promise.all([
client.fetchWithX402('https://api.example.com/resource-1'),
client.fetchWithX402('https://api.example.com/resource-2'),
client.fetchWithX402('https://api.example.com/resource-3'),
]);
// Each request handles payment independently
console.log(await result1.json());
console.log(await result2.json());
console.log(await result3.json());Environment Compatibility
The SDK works in any environment with a global fetch implementation:
💻
Node.js 18+
Uses global fetch
🌐
Browser
React, Next.js, etc.
⚡
Edge
Vercel Edge, Cloudflare
Older Node.js Versions
For Node.js < 18, provide a custom fetch implementation:
typescript
import nodeFetch from 'node-fetch';
const client = createAgentClient({
gatewayBaseUrl: '...',
apiKey: '...',
fetchImpl: nodeFetch as unknown as typeof fetch,
});