# POST /v1/score

> Score any URL for AI readability — get penalties, benefits, and ranked recommendations.

Source: https://docs.buildonto.dev/api/score
Section: Read API

---

POST /v1/score\[01\]

## POST /v1/score

Score any URL for AI readability — get penalties, benefits, and ranked recommendations.

**Same engine as the public scanner** at `buildonto.dev/api/aio`, gated by a Bearer token. Subtractive penalty model — perfect = 100, each issue subtracts. Costs 0 credits, but it still takes a concurrency slot. Never cached.

Through the API, every page without the Onto SDK takes the −10 `Unmanaged AI Payload` penalty, so scores top out at 90 without the SDK.

### Endpoint

\[02\]


```
POST https://api.buildonto.dev/v1/score
Authorization: Bearer onto_sk_live_YOUR_KEY
Content-Type: application/json
```

### Request body

\[03\]

urlstringreq

Public URL to fetch and score.

### Response

\[04\]


```
{
  "status": "success",
  "url": "https://stripe.com",
  "aio_score": 90,
  "grade": "Excellent",
  "hallucination_risk": "low",
  "insights": {
    "robots_allowed": true,
    "waf_blocked": false,
    "markdown_supported": true,
    "json_ld_present": true,
    "semantic_hierarchy": true
  },
  "penalties": [
    "Warning: Unmanaged AI Payload. Native Markdown is present but lacks Onto-specific brand controls, versioning, and agent analytics."
  ],
  "benefits": [
    "Native Markdown Support: This site natively serves Markdown to agents, which improves extraction but lacks the Onto-optimized management layer.",
    "Payload Optimization: Native Markdown reduced the agent payload to 14.8KB, eliminating ~98% of visual noise."
  ],
  "recommendations": [
    {
      "priority": "Medium",
      "title": "Migrate to Onto SDK",
      "description": "Native Markdown detected but lacks agent analytics and policy controls. Upgrade to the Onto layer."
    }
  ],
  "stats": { "raw_size": "605KB", "efficiency": "97.6%", "extraction_time_ms": 412 },
  "bot_preview": "# Stripe — Online payments…\n\n…"
}
```

`penalties`, `benefits` and `recommendations` are drawn from a fixed set of scorer strings — they are not free-form. Note that `benefits` describes what the Onto layer contributes, so some entries appear precisely _because_ the page is missing something (the JSON-LD benefit, for instance, is emitted only when no JSON-LD is found). `insights` always carries exactly these five booleans.

**PDF and text URLs are not scored.** The AIO scorer grades HTML structure, so a URL that resolves to a PDF or a text format (JSON, CSV, XML, plain text) returns `aio_score`, `grade` and `hallucination_risk` as `null`, `insights` as `{ "pdf_text_extracted": true }`, empty `penalties` / `benefits` / `recommendations`, `stats.efficiency` as the literal string `"—"`, `bot_preview` as `""`, and an extra top-level `note` field.

### Response headers

\[05\]

Header · Description

`X-RateLimit-Remaining`

Monthly plan credits left. Score does not reduce it.

`X-RateLimit-Reset`

When monthly plan credits reset (end of the UTC month).

`X-Onto-Billed`

Always “plan” — score costs 0 credits.

`X-Concurrent-Remaining`

Concurrency slots still free on your account.

`/v1/score` has no cache layer, so — unlike [/v1/read-and-score](/api/read-and-score) — it does not send `X-Onto-Cache`. It never bills credits, so it never sends `X-Credits-Remaining`.

Because it costs 0 credits, `RATE_LIMITED` and `PAYMENT_REQUIRED` cannot happen here. `CONCURRENT_LIMIT` can. The robots.txt override for domains you own does not apply on this endpoint, so a site that blocks Onto returns `ROBOTS_BLOCKED` even if you own it. See [error codes](/api/errors).

### Grade ranges

\[06\]

Score · Grade

90–100\[Excellent\]

75–89\[Good\]

50–74\[Needs work\]

25–49\[AI-hostile\]

0–24\[Invisible\]

`hallucination_risk` is computed from the score _and_ the insights, not from the grade band — a grade does not map to a fixed risk. It is `high` if robots.txt disallows AI agents, or the score is under 50, or the page has neither JSON-LD nor a semantic heading hierarchy; `medium` if the score is under 80, or any of `markdown_supported`, `json_ld_present` or `semantic_hierarchy` is false; and `low` otherwise.

### Examples

\[07\]


```
curl -X POST https://api.buildonto.dev/v1/score \
  -H "Authorization: Bearer $ONTO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://stripe.com"}'
```

Copy as Markdown[](/api/score.md "Open the raw Markdown")

---
## Structured Data (JSON-LD)
```json
{
  "@context": "https://schema.org",
  "@type": "WebSite",
  "name": "Onto Docs",
  "url": "https://docs.buildonto.dev",
  "description": "How to use Onto: serve AI agents Markdown from your Next.js site, call the Read API, connect over MCP, and read the AIO score.",
  "inLanguage": "en",
  "publisher": {
    "@type": "Organization",
    "name": "Onto",
    "url": "https://buildonto.dev"
  }
}
```