REST API

The REST API exposes three public endpoints for scoring content, listing models, and inspecting a model's traits. This page documents the request and response shapes, failure modes, and examples for each endpoint.

Base URL and request format

Base URLhttps://u22a8.ai
AuthenticationNone required for the three public endpoints described below.
Request content typeapplication/json for structured requests. The score endpoint also accepts text/plain bodies containing raw text or a URL.
Response content typeapplication/json by default. text/plain is available on the score and traits endpoints via the Accept header.
Rate limit10 requests per 10 seconds per client. Requests beyond this limit receive HTTP 429.

Common failure modes

The following status codes are returned by all endpoints. Endpoint-specific failures are documented per endpoint in §3.

StatusCondition
404The model handle in the path does not exist.
422The request body is malformed, empty (where a body is required), or contains a URL that cannot be fetched or extracted.
429The client has exceeded the rate limit.
503The service is temporarily unavailable. Retry after a short delay.

Error responses carry a JSON body with a detail field describing the cause:

{ "detail": "Profile 'u22a8.unknown' not found" }

Endpoints

POST /p/{handle}

Score content against a profile's traits. The request body carries the content to score (literal text or a URL). The response contains per-trait scores with scoring context, the composite score, overall confidence, and headroom.

Path parameters
NameTypeDescription
handlestringModel handle, e.g. u22a8.technical-writing. Required. See GET /profiles for the list.
Request body — application/json
FieldTypeDescription
contentstringRequired. Text to score, or a URL to fetch and score. URLs are detected automatically.
compare_tostringOptional. Baseline text or URL. When present, the response includes baseline scores and a delta.
traitsarray of stringsOptional. Restrict scoring to the named traits. Omit to score all traits on the model.
Request body — text/plain

The endpoint also accepts a raw text/plain body containing either the content to score or a URL. This form is equivalent to a JSON body with only content set; compare_to and traits are not available in this form.

Response — application/json (200)
{ "scores": { "clarity": 72, "specificity": 84, "verification": 58 }, "composite": 69, "confidence": "high", "headroom": 14, "input_tokens": 240, "detail": { "clarity": { "score": 72, "label": "Solid", "confidence": "high", "band": [68, 76], "headroom": 8, "breaks": { "developing": 42, "solid": 65, "strong": 80 } } // …one entry per scored trait } // compare_to and delta appear when compare_to is provided in the request }

All per-trait fields are defined on the score card, tiers, confidence, headroom, and breaks pages. label and headroom are null when confidence is low.

Endpoint-specific failures
422The body is empty, not valid JSON, references traits that do not exist on the model, or includes a URL that cannot be fetched or extracted.
Example — curl
# Text body, JSON response curl -s -X POST https://u22a8.ai/p/u22a8.technical-writing \ -H "Content-Type: application/json" \ -d '{"content":"The function retries 5xx responses up to three times..."}' # URL body, plain-text response curl -s -X POST https://u22a8.ai/p/u22a8.compelling-readme \ -H "Accept: text/plain" \ -H "Content-Type: text/plain" \ --data-binary "https://github.com/astral-sh/uv"
Example — python (httpx)
import httpx r = httpx.post( "https://u22a8.ai/p/u22a8.technical-writing", json={"content": "The function retries 5xx responses up to three times..."}, timeout=30, ) r.raise_for_status() data = r.json() print(data["composite"], data["confidence"]) for trait, detail in data["detail"].items(): print(trait, detail["score"], detail["label"])
GET /profiles

List the public models available for scoring. Each entry identifies a model by handle and summarizes its traits.

Request

No parameters. No request body.

Response — application/json (200)
{ "profiles": [ { "handle": "u22a8.technical-writing", "description": "Scores technical prose for clarity and specificity", "traits": ["Clarity", "Specificity", "Verification"] } // …one entry per public model ] }
Example — curl
curl -s https://u22a8.ai/profiles
Example — python (httpx)
import httpx profiles = httpx.get("https://u22a8.ai/profiles", timeout=10).json()["profiles"] for p in profiles: print(p["handle"], "-", p["description"])
GET /p/{handle}/traits

Inspect the traits defined on a model. Returns each trait's name, description, polarity labels, and training sample counts.

Path parameters
NameTypeDescription
handlestringModel handle. Required.
Response — application/json (200)
{ "traits": [ { "key": "clarity_and_simplicity", "name": "Clarity", "description": "How readily the prose conveys its claim", "positive_label": "Clear", "negative_label": "Obscure", "sample_count": 20, "positive_samples": 10, "negative_samples": 10 } // …one entry per trait on the model ] }
Accept: text/plain

A plain-text response, suitable for terminal display, is returned when the Accept header includes text/plain.

Example — curl
curl -s https://u22a8.ai/p/u22a8.technical-writing/traits curl -s -H "Accept: text/plain" https://u22a8.ai/p/u22a8.technical-writing/traits
Example — python (httpx)
import httpx traits = httpx.get( "https://u22a8.ai/p/u22a8.technical-writing/traits", timeout=10, ).json()["traits"] for t in traits: print(t["name"], "—", t["positive_label"], "/", t["negative_label"])

OpenAPI schema

A machine-readable OpenAPI schema for all endpoints is served at /api-docs. The schema and this page describe the same endpoints; the schema is authoritative for field types and nullability.

  • MCP — the same scoring functions, exposed as MCP tools to any MCP-compatible client.
  • GitHub Action — a packaged way to score content from CI.
  • Score card — how the response fields render together.
Scores are approximate — not a substitute for human judgment.