@bfcmath/x402-sdk
v0.1.0
Published
Typed client SDK for OptimAI x402-paid search endpoints.
Maintainers
Readme
@bfcmath/x402-sdk
Typed client SDK for the api-server-onchain x402 search endpoints.
It wraps the 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 @bfcmath/x402-sdkQuick start
import {
createOptimaiX402Client,
createViemPaymentHandler,
} from "@bfcmath/x402-sdk";
const paymentHandler = createViemPaymentHandler({
privateKey: process.env.X402_PAYER_PRIVATE_KEY!,
rpcUrls: {
"eip155:84532": "https://sepolia.base.org",
},
});
const client = createOptimaiX402Client({
baseUrl: "http://localhost:3002",
paymentHandler,
});
const { search, paymentContext } = await client.createSearch({
query: "What is liquidation?",
});
const completed = await client.waitForSearchCompletion(search.id, {
paymentContext,
});
console.log(completed.result?.answer);API
createOptimaiX402Client(config)
Creates the high-level SDK client.
Methods:
createSearch(input, options?)getSearch(id, options?)cancelSearch(id, options?)waitForSearchCompletion(id, options?)rememberPaymentContext(context)forgetPaymentContext(id)
createViemPaymentHandler(config)
Creates a payment handler backed by @x402/evm, @x402/fetch, and viem.
Built-in network support:
eip155:8453-> Baseeip155:84532-> Base Sepolia
Persisting search 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 test
The package includes a smoke script for testing the built SDK against a live OptimAI x402 endpoint:
X402_PAYER_PRIVATE_KEY=0x... pnpm smoke:localWhat to pass:
X402_PAYER_PRIVATE_KEYmust be the payer wallet private key used to sign the x402 payment payload- this is a normal EVM wallet private key: 32-byte hex, with or without
0x - it is not a server key, not a Coinbase facilitator key, and not an API key
If you use MetaMask:
- use the private key for the account that should pay for the x402 request
- in MetaMask, export the account private key and pass that exported value as
X402_PAYER_PRIVATE_KEY - the account should have enough funds on the chain required by the server challenge
- treat this key as highly sensitive and only use it in a secure local/dev environment you control
Defaults:
OPTIMAI_X402_BASE_URL=https://api-onchain.optimai.network- mainnet RPC for
eip155:8453defaults tohttps://mainnet.base.org
Optional overrides:
OPTIMAI_X402_QUERY="What is liquidation?"OPTIMAI_X402_BASE_URL=http://localhost:3002X402_RPC_URL_BASE=https://mainnet.base.orgX402_RPC_URL_BASE_SEPOLIA=https://sepolia.base.orgOPTIMAI_X402_RUN_CANCEL=1
Local compatibility test
For a stronger end-to-end check against api-server-onchain, use:
X402_PAYER_PRIVATE_KEY=0x... OPTIMAI_X402_BASE_URL=http://localhost:3002 pnpm compat:localThis script validates the full x402 contract described in the server integration notes:
- create a paid search with query
Compare ETH and BTC - open
GET /external/v1/x402/search/:id/eventsusing the stored originalpayment-signature - wait for
search.completedandsearch.done - verify the completed SSE answer matches the final
GET /external/v1/x402/search/:idanswer - create a second search and verify
DELETE /external/v1/x402/search/:id - verify the cancelled search later returns:
status: "cancelled"x402_payment_status: "voided"
If the script finishes with:
[result]
Compatibility test completed successfully.then the SDK and the current api-server-onchain implementation are compatible for the tested create, SSE, GET, and DELETE flows.
Manual release checklist
First release is intentionally manual. From the package root:
pnpm install
pnpm build
pnpm test
X402_PAYER_PRIVATE_KEY=0x... OPTIMAI_X402_BASE_URL=http://localhost:3002 pnpm compat:local
pnpm packWhat to verify before publish:
pnpm buildsucceedspnpm testsucceedspnpm compat:localsucceeds against a runningapi-server-onchainpnpm packproduces the tarball without missing entrypoints or type declarations
Publish steps:
npm whoami
npm publish --access publicPost-publish verification:
mkdir -p /tmp/optimai-x402-sdk-smoke
cd /tmp/optimai-x402-sdk-smoke
pnpm init
pnpm add @bfcmath/x402-sdkThen import createOptimaiX402Client and createViemPaymentHandler from the installed package and run a smoke request against api-server-onchain.
