Agent Friendly
API DOCUMENTATION

Measure a site.
Give your agent the next fix.

A public HTML score, evidence, and actionable improvements.

Analyze any public website

Use your app’s confirmed Supabase session token. The URL is normalized to a domain, checked across representative public pages, and saved to your Builder dashboard.

curl "$AF_ORIGIN/api/analyze" \
  -H "Authorization: Bearer $AF_SESSION_TOKEN" \
  -H 'Content-Type: application/json' \
  --data '{"url":"https://example.com/products/item"}'

AF_ORIGIN is your deployed origin, or http://localhost:3100 locally. Export a current access token obtained through your own app sign-in. Do not put tokens in URLs or source control.

{ "id": "JOB_ID", "domain": "example.com", "status": "queued", "saved": true }

This is a fictional response. Poll GET /api/jobs/JOB_ID every two seconds. A complete job has a run_id; retrieve GET /api/runs/RUN_ID. A cached response already has the run ID and needs no polling.

Use the portable client

import { analyzeURL } from './api-client.js';
const report = await analyzeURL({
  origin: process.env.AF_ORIGIN,
  url: 'https://example.com',
  token: process.env.AF_SESSION_TOKEN,
  onJob: job => console.log(job.status)
});
console.log(report.score, report.coverage, report.recommendations);

Download the client above. It works in Node 22+ or a browser, bounds polling, respects Retry-After and attempts recovery if a job expires. A failed check stays unscored; inspect its coverage rather than treating null as zero.

Choose the right endpoint

EndpointAccessBehavior
POST /api/analyzeConfirmed sessionAnalyze + save. Fresh measured results reused for six hours. refresh:true uses a one-minute cooldown.
POST /api/benchmarksSession or configured benchmark keyCLI remeasurement. Five-minute cooldown. No dashboard save.
POST /api/discoverPublicAdd a domain; normally return indexed results. No private saved-site access.
GET /api/jobs/:id
GET /api/runs/:id
GET /api/sites/:domain
PublicRead job state, immutable run or site history.

Never use a Supabase service-role key as a user bearer token. Session tokens expire: refresh through Supabase, then retry a rejected request. A deployment benchmark key is accepted only by the benchmark route.

Five states. One clear outcome.

queued → running → complete → GET /api/runs/:run_id
cached → GET /api/runs/:run_id
failed → inspect error; retry later

Jobs are in memory and expire six hours after completion or on server restart. Keep the job ID and domain when polling times out. Use GET /api/sites/:domain to recover a newly completed result, or request a new check. Runs retain the last 120 per site; they are not stored forever.

Only status: measured with a numeric score represents a full basic result. limited and unavailable have no score. At least five readable pages are required. No login, checkout, payment or CAPTCHA bypass is performed.

Errors you can handle

{
  "error": "Sign in to continue.",
  "code": "UNAUTHORIZED",
  "request_id": "server-generated-request-id"
}

Every response includes X-Request-ID. Errors repeat it in the body so a client can report a specific request without disclosing credentials.

StatusNext action
400 / 413Correct the public URL or reduce the JSON body to 4,096 characters.
401Sign in with a confirmed account or refresh your session.
404Check the identifier; expired jobs may still have saved site results.
429Wait for Retry-After seconds. Do not retry in a tight loop.
503Retry later; account, persistence or service setup may be unavailable.

The beta limits benchmark requests to 12 per hour per socket IP and brand search to 20 per minute. Shared networks share these limits. The catalog has a 500-site capacity. Private and loopback destinations, credential-bearing URLs and custom ports are rejected. Redirect destinations are checked too.

Keep a baseline. Compare the evidence.

AGENT_FRIENDLY_URL=https://YOUR_HOST \
  npm run harness -- example.com BASELINE_RUN_ID

The harness runs from the source checkout. Set the server’s configured private benchmark key as BENCHMARK_API_KEY for CLI access. Compare the same domain, profile and benchmark version after the five-minute cooldown. A score change is not evidence of a sales change.

The server schedules tracked sites every six hours and resumes overdue checks on restart. Use one scheduler with persistent storage. Deep Agentic Rubric is a separate engineering specification; a readable HTML score does not certify idempotency, delegated authorization or partner checkout.

Send a concrete observation

Discover an active verified-owner inbox with GET /api/feedback-target/example.com. Use the feedback schema and avoid private buyer data.

POST /api/feedback
Content-Type: application/json

{
  "domain": "example.com",
  "kind": "agent",
  "agent_name": "Site review agent",
  "topic": "Other",
  "message": "Dispatch and arrival times are not distinguished.",
  "page_url": "https://example.com/shipping"
}

Agent identity is self-reported. Feedback stays separate from measured scores. Only a verified owner can read the private inbox. Write feedback that can become a fix ↗