x402 SDK
Use the OptimAI x402 SDK to create paid searches and keep access across agents.
@optimai-network/x402-sdk
is a typed client SDK for OptimAI x402 search endpoints.
It wraps two awkward parts of the flow:
- the initial
402 Payment Requiredchallenge - the follow-up
payment-signatureheader generation
It also returns a serializable paymentContext object, including the original
payment-signature, so another agent or process can keep working with the same
paid search later.
Install
pnpm add @optimai-network/x402-sdkQuick start: EVM / Base
import {
createOptimaiX402Client,
createViemPaymentHandler,
} from "@optimai-network/x402-sdk"
const paymentHandler = createViemPaymentHandler({
privateKey: process.env.X402_EVM_PAYER_PRIVATE_KEY!,
rpcUrls: {
"eip155:8453": "https://mainnet.base.org",
"eip155:84532": "https://sepolia.base.org",
},
})
const client = createOptimaiX402Client({
baseUrl: "https://api-onchain.optimai.network",
paymentHandler,
})
const { search, paymentContext } = await client.createSearch({
query: "What is liquidation?",
})
const completed = await client.waitForSearchCompletion(search.id, {
paymentContext,
})
console.log(completed.result?.answer)X402_EVM_PAYER_PRIVATE_KEY is the payer wallet private key used to sign the
x402 payment payload. It is not a server key, not a Coinbase facilitator key,
and not an API key.
Quick start: Solana
import {
createOptimaiX402Client,
createSolanaPaymentHandler,
} from "@optimai-network/x402-sdk"
const paymentHandler = createSolanaPaymentHandler({
privateKey: process.env.X402_SOLANA_PAYER_PRIVATE_KEY!,
rpcUrls: {
"solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp": "https://api.mainnet-beta.solana.com",
"solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1": "https://api.devnet.solana.com",
},
})
const client = createOptimaiX402Client({
baseUrl: "https://api-onchain.optimai.network",
paymentHandler,
})
const { search, paymentContext } = await client.createSearch({
query: "What is liquidation?",
})
const completed = await client.waitForSearchCompletion(search.id, {
paymentContext,
})
console.log(completed.result?.answer)X402_SOLANA_PAYER_PRIVATE_KEY is the Solana payer wallet private key used to
sign the x402 payment payload. The payer wallet needs enough USDC for the
payment and enough SOL to pay Solana network fees.
Client methods
createOptimaiX402Client(config) creates the high-level SDK client.
Available methods:
createSearch(input, options?)getSearch(id, options?)cancelSearch(id, options?)waitForSearchCompletion(id, options?)rememberPaymentContext(context)forgetPaymentContext(id)
Payment handlers
createViemPaymentHandler(config) creates a payment handler backed by
@x402/evm, @x402/fetch, and viem.
Built-in network support:
| CAIP-2 | Network |
|---|---|
eip155:8453 | Base |
eip155:84532 | Base Sepolia |
createSolanaPaymentHandler(config) creates a payment handler backed by the
Solana x402 path.
Built-in Solana network support:
| CAIP-2 | Network |
|---|---|
solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp | Solana mainnet |
solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1 | Solana devnet |
Payment requirements and payTo
SDK users do not manually set payTo, amount, asset, network, or Solana
feePayer values in normal usage. Those values come from the OptimAI server's
402 Payment Required challenge.
The SDK reads the server challenge, chooses the first supported payment option
for the handler you configured, signs the payment, and retries the paid request.
If your app needs to display the receiver or payment details, inspect
paymentContext.paymentRequired.accepts after createSearch().
Payment statuses
x402_payment_status in responses can be:
| Status | Meaning |
|---|---|
verified_unsettled | Payment is verified, but settlement is not finalized in OptimAI yet. A chain transfer may already exist while the server is still confirming and persisting the settlement ID. |
settled | Settlement is finalized and the settlement ID, usually a transaction hash, is persisted. |
voided | Payment was voided, usually because the request was cancelled or failed before settlement. |
settlement_failed | The server exhausted settlement retries and needs manual or operator follow-up. |
Persist access across agents
GET /external/v1/x402/search/:id works best when the client replays the exact
original payment-signature used for the paid create call.
Because of that, the SDK returns:
type SearchPaymentContext = {
id: string
paymentRequired: X402PaymentRequired
paymentSignature?: string
}Persist this object alongside the search ID if another agent or process will poll or fetch the search later:
const { search, paymentContext } = await client.createSearch({ query: "..." })
// Store paymentContext somewhere durable.
client.rememberPaymentContext(paymentContext)
const latest = await client.getSearch(search.id)If you retry createSearch() with the same Idempotency-Key from another
process, pass the previously stored context back in options.existingPaymentContext
so the SDK can authenticate the 303 redirect target with the original
signature:
const retry = await client.createSearch(
{ query: "..." },
{
idempotencyKey: "search-123",
existingPaymentContext: paymentContext,
}
)Local smoke tests
The package includes a smoke script for testing the built SDK against a live OptimAI x402 endpoint:
X402_EVM_PAYER_PRIVATE_KEY=0x... pnpm smoke:local:evmFor backward compatibility, pnpm smoke:local still runs the EVM smoke path.
Solana smoke testing is optional and additive:
X402_SOLANA_PAYER_PRIVATE_KEY='[...]' pnpm smoke:local:solanaDefaults:
OPTIMAI_X402_BASE_URL=https://api-onchain.optimai.network- mainnet RPC for
eip155:8453defaults tohttps://mainnet.base.org - Solana mainnet RPC defaults to
https://api.mainnet-beta.solana.com
Optional overrides:
OPTIMAI_X402_QUERY="What is liquidation?"OPTIMAI_X402_BASE_URL=http://localhost:3002X402_EVM_BASE_RPC_URL=https://mainnet.base.orgX402_EVM_BASE_SEPOLIA_RPC_URL=https://sepolia.base.orgX402_SOLANA_MAINNET_RPC_URL=https://api.mainnet-beta.solana.comX402_SOLANA_DEVNET_RPC_URL=https://api.devnet.solana.comX402_PAYER_PRIVATE_KEY=0x...for legacy EVM setupsX402_RPC_URL_BASE=https://mainnet.base.orgX402_RPC_URL_BASE_SEPOLIA=https://sepolia.base.orgX402_RPC_URL=https://mainnet.base.orgOPTIMAI_X402_RUN_CANCEL=1