@lucidai/pay
v0.3.0
Published
Drop-in fetch() replacement that handles x402 payments automatically
Maintainers
Readme
@lucidai/pay
Drop-in fetch() replacement with automatic x402 payments for AI agents. Multi-chain: Base, Ethereum, Arbitrum, Optimism, Polygon, ApeChain, Monad, Solana, Sui.
Install
npm install @lucidai/payQuick Start
import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { base } from "viem/chains";
import { createLucidFetch, ViemWallet } from "@lucidai/pay";
const client = createWalletClient({
account: privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`),
chain: base,
transport: http(),
});
const lucidFetch = createLucidFetch({
wallet: new ViemWallet(client),
maxAmountPerRequest: "100000", // 0.10 USDC (6 decimals)
});
// Use exactly like fetch() -- payments are handled automatically
const response = await lucidFetch(
"https://api.lucid.foundation/v1/chat/completions",
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
model: "gpt-4o",
messages: [{ role: "user", content: "Hello" }],
}),
},
);How It Works
- Your request is sent to the API as a normal
fetch()call. - If the server returns HTTP 402, the response body contains an x402 v2
options[]array — one entry per supported chain and facilitator, each with the recipient address, token, amount, and chain. @lucidai/payselects the option matching your wallet's chain (or falls back to the first option), checks the amount against your budget, sends an on-chain USDC transfer, and retries withX-Payment-Proof(tx hash) andX-Payment-Chainheaders.- The server delegates verification to the appropriate facilitator and returns the response.
Works with any x402-enabled API, including Lucid TrustGate and MCPGate endpoints.
Supported Chains
| Chain | Token | Facilitators | |-------|-------|-------------| | Base | USDC | Direct, Coinbase, PayAI, Thirdweb | | Ethereum | USDC | PayAI, Thirdweb | | Arbitrum | USDC | PayAI, Thirdweb | | Optimism | USDC | PayAI, Thirdweb | | Polygon | USDC | Thirdweb | | ApeChain | USDC | Thirdweb | | Monad | USDC | Direct, PayAI, Thirdweb | | Solana | USDC | PayAI | | Sui | USDC | Sui (native) |
API Reference
createLucidFetch(config): lucidFetch
Returns a configured fetch function that handles x402 payments automatically.
const lucidFetch = createLucidFetch(config);
const response = await lucidFetch(url, init);lucidFetch(url, init?, config?)
One-shot convenience function. Accepts an inline config as the third argument. If no config is provided, behaves as a standard fetch().
import { lucidFetch } from "@lucidai/pay";
const response = await lucidFetch(
"https://api.lucid.foundation/v1/chat/completions",
{ method: "POST", body: "..." },
{ wallet: myWallet },
);Configuration (LucidPayConfig)
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| wallet | PaymentWallet | required | Wallet adapter used for payments |
| maxAmountPerRequest | string | no limit | Maximum amount per request in micro-units (USDC has 6 decimals, so "1000000" = 1 USDC) |
| maxRetries | number | 1 | Number of retries after payment |
| onPayment | (info: PaymentInfo) => void | -- | Called after a successful payment |
| onPaymentSkipped | (info) => void | -- | Called when a payment exceeds the budget |
Per-Request Overrides (LucidFetchOptions)
Extends standard RequestInit. You can override the wallet or budget on individual requests:
const response = await lucidFetch(url, {
method: "POST",
body: "...",
wallet: alternateWallet, // override wallet for this call
maxAmount: "50000", // override budget for this call
});PaymentInfo
Object passed to the onPayment callback:
| Field | Type | Description |
|-------|------|-------------|
| txHash | string | On-chain transaction hash |
| amount | string | Amount paid (micro-units) |
| recipient | string | Payment recipient address |
| chain | string | Chain identifier (e.g. "base-sepolia") |
| token | string | Token symbol (e.g. "USDC") |
| url | string | The URL that required payment |
Wallets
ViemWallet (production)
Wraps a viem WalletClient to sign and send real ERC-20 transfers on-chain. Consumers bring their own viem dependency.
import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { base } from "viem/chains";
import { ViemWallet } from "@lucidai/pay";
const wallet = new ViemWallet(
createWalletClient({
account: privateKeyToAccount("0x..."),
chain: base,
transport: http(),
}),
);MemoryWallet (testing)
In-memory wallet that records payments without sending real transactions. Useful for tests and local development.
import { MemoryWallet } from "@lucidai/pay";
const wallet = new MemoryWallet("0xYourAddress", "base-sepolia");
// After running requests:
console.log(wallet.payments); // array of recorded paymentsCustom Wallets
Implement the PaymentWallet interface to use any signing backend:
import type { PaymentWallet } from "@lucidai/pay";
const myWallet: PaymentWallet = {
address: "0x...",
chain: "base",
async sendPayment({ to, amount, tokenAddress, chain }) {
// Sign and broadcast an ERC-20 transfer
return txHash;
},
};License
MIT
