AttestPage · Docs · Pricing · OpenAPI · llms.txt

OpenAI Agents SDK: check a quote before citing it, paid per call

Last updated: 2026-10-17

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 sends no payment and returns the price for each call. With ATTESTPAGE_X402_KEY set, it pays each call with x402 through @x402/fetch, and refuses any offer above its limit.

For the same check in other frameworks, see LangChain, LlamaIndex, Vercel AI SDK and Claude Agent SDK.

Install

Node.js 20 or later.

npm init -y && npm pkg set type=module
npm install @openai/agents zod
npm install @x402/fetch@2.28.0 @x402/evm@2.28.0 viem@2.57.4   # 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 wallet holding a little USDC (real money). The key stays in this process.

attestpage.mjs

// AttestPage client for agent tools. With no key it sends no payment. With ATTESTPAGE_X402_KEY
// it pays each call with x402 on Base (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://s2h6qt73jtzlgbgnnfacln2poq.srv.us').replace(/\/+$/, '');
const NETWORK = process.env.ATTESTPAGE_NETWORK || 'eip155:8453'; // Base; ATTESTPAGE_NETWORK picks another network the 402 lists
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 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 }),
    checkPackages: ({ packages }) => call('/v1/check/packages', { packages }),
    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. 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                             # no key: returns the price
ATTESTPAGE_X402_KEY=0x... node openai-agents-sdk.mjs   # pays US$0.01 per verify_quote in USDC

What comes back

Check packages before install

attestpage.checkPackages checks up to 10 package names on npm, PyPI or crates.io in one call, for US$0.005 per batch. Give it to the agent as a tool, the same way as checkLinks, so the agent checks a package a model suggested before it installs one:

const checkPackages = tool({
  name: 'check_packages',
  description: 'Check that npm, PyPI or crates.io names exist before installing them.',
  parameters: z.object({
    packages: z.array(z.object({ ecosystem: z.enum(['npm', 'pypi', 'crates']), name: z.string(), version: z.string().nullable().optional() })).min(1).max(10),
  }),
  // Strict mode can send version as null; the route accepts a version string or no version at all.
  execute: async ({ packages }) => attestpage.checkPackages({
    packages: packages.map(({ version, ...p }) => (version ? { ...p, version } : p)),
  }),
});

exists is true when the registry lists the name, false when it does not, and null when the lookup failed. It is not a security verdict. The full answer is at [/docs/check-packages](https://s2h6qt73jtzlgbgnnfacln2poq.srv.us/docs/check-packages).

Prices are per call in USDC. The full list is at [/pricing.json](https://s2h6qt73jtzlgbgnnfacln2poq.srv.us/pricing.json).