OpenAI Agents SDK: check a quote before citing it, paid per call
Last updated: 2026-10-10
An OpenAI Agents SDK agent with two AttestPage tools: verify_quote (US$0.01 a call) and check_links (US$0.005 per batch of up to 10 URLs). With no key, the client uses the free trial and returns the price when a call needs payment. With ATTESTPAGE_X402_KEY set, it pays each call with x402 through @x402/fetch, and refuses any offer above its limit.
Install
Node.js 20 or later.
npm init -y && npm pkg set type=module
npm install @openai/agents zod
npm install @x402/fetch @x402/evm viem # only needed to pay
export OPENAI_API_KEY=...
To pay, set ATTESTPAGE_X402_KEY to the private key (0x and 64 hex digits) of a Base Sepolia wallet made only for testing, holding test USDC. The key stays in this process.
attestpage.mjs
// AttestPage client for agent tools. With no key it sends the free-trial header. With ATTESTPAGE_X402_KEY
// it pays each call with x402 on Base Sepolia (test USDC), up to MAX_USD a call. A 402 it does not pay
// comes back as { payment_required, price_usd, network } instead of an exception.
const BASE = (process.env.ATTESTPAGE_URL || 'https://vehcdj664efetfrsolne5umanq.srv.us').replace(/\/+$/, '');
const NETWORK = 'eip155:84532'; // Base Sepolia
const MAX_USD = Number(process.env.MAX_USD || '0.01'); // the most one call may cost
// A fetch that answers 402 offers with a payment signed by key. Loaded only when a key is set.
async function payingFetch(key) {
const [{ wrapFetchWithPayment, x402Client }, { registerExactEvmScheme }, { privateKeyToAccount }] = await Promise.all([
import('@x402/fetch'), import('@x402/evm/exact/client'), import('viem/accounts'),
]);
const client = new x402Client();
registerExactEvmScheme(client, { signer: privateKeyToAccount(key) });
// Sign only offers on Base Sepolia at or under MAX_USD (amounts are USDC with 6 decimals).
client.registerPolicy((_version, reqs) => reqs.filter((r) => r.network === NETWORK && Number(r.amount) <= MAX_USD * 1e6));
return wrapFetchWithPayment(fetch, client);
}
function offer(header) {
try {
const first = JSON.parse(Buffer.from(header, 'base64').toString('utf8')).accepts[0];
return { price_usd: Number(first.amount) / 1e6, network: first.network };
} catch {
return {};
}
}
export async function createClient({ key = process.env.ATTESTPAGE_X402_KEY } = {}) {
const fetchFn = key ? await payingFetch(key) : fetch;
async function call(path, body, { trial = !key } = {}) {
const headers = { 'content-type': 'application/json', accept: 'application/json' };
if (trial) headers['quoteproof-trial'] = '1';
let res;
try {
res = await fetchFn(`${BASE}${path}`, { method: 'POST', headers, body: JSON.stringify(body) });
} catch (err) {
// @x402/fetch throws when no offer passes the policy, or when signing fails.
return { error: 'payment_not_made', message: String(err?.message ?? err) };
}
const json = await res.json().catch(() => ({}));
if (res.ok) return json;
// The trial is used up for today: ask again without it, for the price.
if (res.status === 429 && trial && json.error?.code === 'trial_exhausted') return call(path, body, { trial: false });
if (res.status === 402) {
return { payment_required: true, ...offer(res.headers.get('payment-required') ?? ''),
message: 'This call needs an x402 payment; set ATTESTPAGE_X402_KEY to pay.' };
}
return { error: json.error?.code ?? `http_${res.status}`, status: res.status, message: json.error?.message ?? '' };
}
return {
verifyQuote: ({ url, quote, match = 'fuzzy' }) => call('/v1/verify/quote', { url, quote, match }),
checkLinks: ({ urls }) => call('/v1/check/links', { urls }),
verifyReceipt: ({ receipt }) => call('/v1/receipt/verify', { receipt }, { trial: false }),
};
}
openai-agents-sdk.mjs
// OpenAI Agents SDK agent that checks a quote with AttestPage before it cites it.
import { Agent, run, tool } from '@openai/agents';
import { z } from 'zod';
import { createClient } from './attestpage.mjs';
const attestpage = await createClient();
const verifyQuote = tool({
name: 'verify_quote',
description: 'Use before quoting a web page: is this exact or near-exact quote on the page at url? '
+ 'Returns result.match (exact, fuzzy or none), page.content_kind and a signed receipt. US$0.01.',
parameters: z.object({ url: z.string(), quote: z.string() }),
execute: async ({ url, quote }) => attestpage.verifyQuote({ url, quote }),
});
const checkLinks = tool({
name: 'check_links',
description: 'Use before putting links in an answer: status, final URL and content_kind for each URL. '
+ 'Up to 10 URLs (3 on the free trial). US$0.005 per batch.',
parameters: z.object({ urls: z.array(z.string()).min(1).max(10) }),
execute: async ({ urls }) => attestpage.checkLinks({ urls }),
});
const agent = new Agent({
name: 'Source checker',
instructions: 'Before you quote a web page, call verify_quote. Cite a quote only when result.match is exact or fuzzy '
+ 'and page.content_kind is real. If a tool returns payment_required, give the price and stop.',
tools: [verifyQuote, checkLinks],
});
const question = process.argv.slice(2).join(' ')
|| 'Does https://www.iana.org/help/example-domains say "These domains may be used as illustrative examples in documents"?';
const result = await run(agent, question);
console.log(result.finalOutput);
Run
node openai-agents-sdk.mjs # free trial
ATTESTPAGE_X402_KEY=0x... node openai-agents-sdk.mjs # pays US$0.01 per verify_quote in test USDC
What comes back
result.match:exact,fuzzyornone. Readpage.content_kindfirst: anoneon abot_wallorjs_shellpage means the page could not be read.receipt: an Ed25519-signed JWS of what was on the page and when.attestpage.verifyReceipt({ receipt })checks it for free.- A paid answer has
"tier": "paid"and"rail": "x402". Payment settles only when the route answers with a status below 400; a bad request is refused before payment.