API for AI Agents — x402 Protocol — USDC on Base

GEO Page Audit API

Send a URL. Pay $1.99 USDC. Get AI citability, authority, and readability scores with actionable fixes. No account. No API key. Pay per request via x402.

$1.99 USDC per audit Base L2 (Chain ID 8453) ~15 second response No auth required

Endpoint

POST https://geonimo.com/api/pay-per-seo-geo-audit
Content-Type: application/json
X-PAYMENT: <x402_payment_proof>

{
  "url": "https://example.com"
}

How it works

1

Hit the endpoint

Send a GET request to the endpoint. Receive a 402 response with x402 payment requirements including amount, wallet address, asset, and network.

2

Pay $1.99 USDC

Sign a USDC TransferWithAuthorization (EIP-3009) on Base. Attach the signed proof in the X-PAYMENT header.

3

Get a report URL

Receive a reportUrl immediately (HTTP 202). Poll it every 5 seconds until status is "completed". Full audit results returned as JSON.

Response flow

Step 1: Immediate response (HTTP 202)

{
  "status": "processing",
  "auditId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "reportUrl": "https://geonimo.com/api/report/f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "message": "Your audit is being processed. Poll the reportUrl every 5 seconds until status is 'completed'.",
  "estimatedTime": "10-20 seconds"
}

Step 2: Poll the report URL

GET https://geonimo.com/api/report/f47ac10b-58cc-4372-a567-0e02b2c3d479

While processing, returns HTTP 202:

{ "status": "processing", "message": "Audit is still being processed. Poll again in 5 seconds." }

When complete, returns HTTP 200:

Step 3: Final audit result

{
  "status": "completed",
  "url": "https://example.com",
  "pageType": "Homepage",
  "title": "Example - The best solution for X",
  "summary": "A SaaS platform that helps companies do X.",
  "overallScore": 64,
  "citability": {
    "score": 58,
    "issues": [
      {
        "issue": "Add an FAQ section",
        "current_state": "No Q&A content found on the page",
        "suggested_fix": "Add 5-8 questions like 'What is Example?' with 2-3 sentence answers"
      },
      {
        "issue": "Include specific statistics",
        "current_state": "Marketing copy without concrete numbers",
        "suggested_fix": "Add metrics like '10,000+ customers' or 'Save 40% on costs'"
      }
    ]
  },
  "authority": {
    "score": 71,
    "issues": [
      {
        "issue": "Add published/updated dates",
        "current_state": "No date information found",
        "suggested_fix": "Add 'Last updated: March 2026' in the footer or meta tags"
      }
    ]
  },
  "readability": {
    "score": 65,
    "issues": [
      {
        "issue": "Add JSON-LD schema markup",
        "current_state": "No structured data found",
        "suggested_fix": "Add Organization schema with name, url, description, logo"
      }
    ]
  },
  "createdAt": "2026-03-20T10:30:00.000Z",
  "completedAt": "2026-03-20T10:30:15.000Z",
  "paidBy": "0x52C54f5b4Ff9B99f7fBB69f1403a4D8CB5572578",
  "poweredBy": "geonimo.com"
}

Scoring dimensions

AI Citability40% weight

Will AI quote this page? Checks for quotable statements, FAQ sections, data points, definitions, lists, and structured comparisons that AI search engines can extract and cite.

Authority & Trust30% weight

Will AI trust this source? Checks for author information, external citations, published/updated dates, expertise depth, brand consistency, and social proof like reviews and testimonials.

AI Readability30% weight

Can AI parse this? Checks heading structure (H1-H3 hierarchy), JSON-LD schema markup, content organization, language clarity, and semantic HTML usage.

Technical details

Audit EndpointPOST https://geonimo.com/api/pay-per-seo-geo-audit
Report EndpointGET https://geonimo.com/api/report/<audit-id> (no auth needed)
MethodPOST (with X-PAYMENT header) or GET (returns 402 with payment requirements)
Price$1.99 USDC per audit
NetworkBase mainnet (eip155:8453, Chain ID 8453)
Payment AssetUSDC — 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
Payment Recipient0x0B273D9fD19971FD8195458486294EFc527C5787
Payment Protocolx402 (HTTP 402 Payment Required)
FacilitatorOpenX402 (https://facilitator.openx402.ai)
Payment HeaderX-PAYMENT (contains signed payment proof)
Response FormatJSON
Response Time10-20 seconds
Auth RequiredNone — pay per request, no API key or account needed
Rate Limit10 requests/minute

x402 payment flow

1. Agent sends GET to https://geonimo.com/api/pay-per-seo-geo-audit — receives HTTP 402 with payment requirements (amount, wallet, asset, network)
2. Agent signs a USDC transfer on Base for $1.99 — uses EIP-3009 TransferWithAuthorization (gasless)
3. Agent sends POST with X-PAYMENT header containing signed payment proof — includes request body with target URL
4. Server verifies payment via OpenX402 facilitator — settles on-chain, runs GPT-5.1 analysis, returns full audit results as JSON

EIP-712 signing (critical)

The most common error is invalid_exact_evm_payload_signature. This happens when the EIP-712 domain or types don't match exactly. You MUST use these exact values:

EIP-712 Domain (USDC on Base)

{
  "name": "USD Coin",
  "version": "2",
  "chainId": 8453,
  "verifyingContract": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
}

WARNING: The name MUST be "USD Coin" (not "USDC"). The version MUST be "2" (not "1"). These are set by the USDC contract on Base and cannot be changed.

EIP-3009 TransferWithAuthorization types

{
  "TransferWithAuthorization": [
    { "name": "from", "type": "address" },
    { "name": "to", "type": "address" },
    { "name": "value", "type": "uint256" },
    { "name": "validAfter", "type": "uint256" },
    { "name": "validBefore", "type": "uint256" },
    { "name": "nonce", "type": "bytes32" }
  ]
}

Authorization values

fromYour agent's wallet address (the payer)
to0x0B273D9fD19971FD8195458486294EFc527C5787 (must match payTo in requirements)
value1990000 (= $1.99 with 6 decimals, must match maxAmountRequired)
validAfter0 (valid immediately)
validBeforeCurrent unix timestamp + 300 (5 minute window)
nonceRandom 32-byte hex value (e.g. 0x + 64 random hex chars)

X-PAYMENT header format

The X-PAYMENT header must contain a JSON object (or base64-encoded JSON) with this structure:

{
  "x402Version": 2,
  "scheme": "exact",
  "network": "eip155:8453",
  "payload": {
    "signature": "0x...",
    "authorization": {
      "from": "0xYourWallet",
      "to": "0x0B273D9fD19971FD8195458486294EFc527C5787",
      "value": "1990000",
      "validAfter": "0",
      "validBefore": "1742500000",
      "nonce": "0x..."
    }
  }
}

Common errors and fixes

invalid_exact_evm_payload_signatureWrong EIP-712 domain. Check: name must be "USD Coin" (not "USDC"), version must be "2", chainId must be 8453, verifyingContract must be the USDC address.
amount_too_lowValue must be at least 1990000 (6 decimals). $1.99 = 1990000.
expiredvalidBefore timestamp has passed. Use current time + 300 seconds.
invalid_signatureThe signature doesn't match the from address. Make sure you're signing with the correct private key.
Recipient mismatchThe "to" field must exactly match payTo: 0x0B273D9fD19971FD8195458486294EFc527C5787 (checksum case matters).

Complete code example (Node.js + viem)

The recommended way to avoid signing errors is to use @x402/fetch or viem directly:

Option A: Using @x402/fetch (recommended)

import { paymentFetch } from "@x402/fetch";
import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { base } from "viem/chains";

const account = privateKeyToAccount("0xYOUR_PRIVATE_KEY");
const walletClient = createWalletClient({
  account,
  chain: base,
  transport: http(),
});

const response = await paymentFetch(
  "https://geonimo.com/api/pay-per-seo-geo-audit",
  {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ url: "https://example.com" }),
  },
  { walletClient }
);

const audit = await response.json();
console.log(audit);

Option B: Using viem directly

import { createWalletClient, http, encodeFunctionData } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { base } from "viem/chains";

const account = privateKeyToAccount("0xYOUR_PRIVATE_KEY");
const walletClient = createWalletClient({
  account, chain: base, transport: http(),
});

// 1. Get payment requirements
const reqRes = await fetch("https://geonimo.com/api/pay-per-seo-geo-audit");
const requirements = await reqRes.json();
const req = requirements.accepts[0];

// 2. Sign EIP-3009 TransferWithAuthorization
const nonce = "0x" + [...crypto.getRandomValues(new Uint8Array(32))]
  .map(b => b.toString(16).padStart(2, "0")).join("");
const validBefore = Math.floor(Date.now() / 1000) + 300;

const signature = await walletClient.signTypedData({
  domain: {
    name: "USD Coin",
    version: "2",
    chainId: 8453,
    verifyingContract: req.asset,
  },
  types: {
    TransferWithAuthorization: [
      { name: "from", type: "address" },
      { name: "to", type: "address" },
      { name: "value", type: "uint256" },
      { name: "validAfter", type: "uint256" },
      { name: "validBefore", type: "uint256" },
      { name: "nonce", type: "bytes32" },
    ],
  },
  primaryType: "TransferWithAuthorization",
  message: {
    from: account.address,
    to: req.payTo,
    value: BigInt(req.maxAmountRequired),
    validAfter: 0n,
    validBefore: BigInt(validBefore),
    nonce: nonce,
  },
});

// 3. Send payment + audit request
const paymentPayload = JSON.stringify({
  x402Version: 2,
  scheme: "exact",
  network: "eip155:8453",
  payload: {
    signature,
    authorization: {
      from: account.address,
      to: req.payTo,
      value: req.maxAmountRequired,
      validAfter: "0",
      validBefore: String(validBefore),
      nonce: nonce,
    },
  },
});

const auditRes = await fetch(
  "https://geonimo.com/api/pay-per-seo-geo-audit",
  {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-PAYMENT": paymentPayload,
    },
    body: JSON.stringify({ url: "https://example.com" }),
  }
);

const audit = await auditRes.json();
console.log(audit);

Option C: Using Coinbase AgentKit

// AgentKit handles x402 natively — just configure your agent
// with a Base wallet and make the request. The SDK handles
// the 402 → sign → retry flow automatically.

Quick test (curl)

Step 1: Get payment requirements

curl https://geonimo.com/api/pay-per-seo-geo-audit

Returns 402 with x402 payment requirements.

Step 2: Pay and get audit

curl -X POST 'https://geonimo.com/api/pay-per-seo-geo-audit' \
  -H 'Content-Type: application/json' \
  -H 'X-PAYMENT: <x402_payment_proof>' \
  -d '{"url": "https://example.com"}'

Compatible with any x402 agent

Coinbase AgentKit
Claude (MCP)
ChatGPT (Plugins)
Devin
Cursor Agent
Replit Agent
Custom agents
Any x402 client

About Geonimo

Geonimo is the leading Generative Engine Optimization (GEO) platform. We help brands track and optimize their visibility across AI search engines including ChatGPT, Claude, Perplexity, and Google AI Overviews. This API exposes our page audit functionality as a pay-per-use service for AI agents.

For full platform access with daily monitoring, competitor tracking, and AI copilot, visit geonimo.com.