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.
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
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.
Pay $1.99 USDC
Sign a USDC TransferWithAuthorization (EIP-3009) on Base. Attach the signed proof in the X-PAYMENT header.
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 Endpoint | POST https://geonimo.com/api/pay-per-seo-geo-audit |
| Report Endpoint | GET https://geonimo.com/api/report/<audit-id> (no auth needed) |
| Method | POST (with X-PAYMENT header) or GET (returns 402 with payment requirements) |
| Price | $1.99 USDC per audit |
| Network | Base mainnet (eip155:8453, Chain ID 8453) |
| Payment Asset | USDC — 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 |
| Payment Recipient | 0x0B273D9fD19971FD8195458486294EFc527C5787 |
| Payment Protocol | x402 (HTTP 402 Payment Required) |
| Facilitator | OpenX402 (https://facilitator.openx402.ai) |
| Payment Header | X-PAYMENT (contains signed payment proof) |
| Response Format | JSON |
| Response Time | 10-20 seconds |
| Auth Required | None — pay per request, no API key or account needed |
| Rate Limit | 10 requests/minute |
x402 payment flow
https://geonimo.com/api/pay-per-seo-geo-audit
— receives HTTP 402 with payment requirements (amount, wallet, asset, network)
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
| from | Your agent's wallet address (the payer) |
| to | 0x0B273D9fD19971FD8195458486294EFc527C5787 (must match payTo in requirements) |
| value | 1990000 (= $1.99 with 6 decimals, must match maxAmountRequired) |
| validAfter | 0 (valid immediately) |
| validBefore | Current unix timestamp + 300 (5 minute window) |
| nonce | Random 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_signature | Wrong 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_low | Value must be at least 1990000 (6 decimals). $1.99 = 1990000. |
expired | validBefore timestamp has passed. Use current time + 300 seconds. |
invalid_signature | The signature doesn't match the from address. Make sure you're signing with the correct private key. |
| Recipient mismatch | The "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
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.