/docs/quickstart
For agent developers

API quickstart

Five minutes from signup to a clean structured AIDocument response. One endpoint, one shape, every URL on the web.

01

Get an API key

Sign up at /signup. The free tier is 2,000 AIDocuments / month, no credit card. Your raw key shows once on the dashboard right after signup; copy it into your password manager. You can mint additional keys (one per environment) at /dashboard/keys.
02

Set it as an env var

Treat keys like any other production secret. Don't commit them. The samples below read from $LYRENTH_KEY /process.env.LYRENTH_KEY /os.environ["LYRENTH_KEY"].
03

Resolve a URL with /v1/aidocument

POST a JSON body with the URL you want resolved. The response is the canonical AIDocument v2 shape (see /docs/aidocument). If we already have the page in our shared index it's served from cache; if not, we fetch, clean, and save it once so the next agent gets it instantly too.
curl
curl -X POST https://api.lyrenth.com/v1/aidocument \
  -H "Authorization: Bearer $LYRENTH_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://en.wikipedia.org/wiki/Web_indexing"}'
python
import os
import requests

KEY = os.environ["LYRENTH_KEY"]
r = requests.post(
    "https://api.lyrenth.com/v1/aidocument",
    json={"url": "https://en.wikipedia.org/wiki/Web_indexing"},
    headers={"Authorization": f"Bearer {KEY}"},
)
doc = r.json()
print(doc["identity"]["title"])
print(doc["signals"]["word_count"], "words")
print(doc["content"]["markdown"][:500])
node
const KEY = process.env.LYRENTH_KEY;

const r = await fetch("https://api.lyrenth.com/v1/aidocument", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ url: "https://en.wikipedia.org/wiki/Web_indexing" }),
});
const doc = await r.json();
console.log(doc.identity.title, doc.signals.word_count + " words");
04

Read the response

Every successful 2xx call returns the same grouped envelope regardless of how the source page was rendered (static HTML, React SPA, JS-hydrated content). One round-trip, no scraping logic on your end. The cache.status field tells you whether this call hit the shared index or triggered a fresh fetch.
{
  "schema": {
    "name":    "AIDocument",
    "version": "2.0",
    "ref":     "aidoc:sha256:7a14e9b2d8f3c901b42e5a77c0f19a34"
  },
  "source": {
    "url":              "https://en.wikipedia.org/wiki/Web_indexing",
    "canonical_url":    "https://en.wikipedia.org/wiki/Web_indexing",
    "fetched_at":       "2026-05-13T...",
    "render_mode":      "static",
    "status_code":      200,
    "freshness_policy": "cache_first"
  },
  "cache": {
    "status":           "hit",
    "origin_contacted": false,
    "body_fetched":     false
  },
  "identity": {
    "title":        "Web indexing - Wikipedia",
    "description":  "...",
    "language":     "en",
    "content_type": "article"
  },
  "content": {
    "markdown": "Web indexing or..."
  },
  "structure": {
    "headings":       [{ "level": 1, "text": "Web indexing" }],
    "links":          [{ "url": "...", "text": "...", "internal": true }],
    "images":         [{ "url": "...", "alt": "..." }],
    "structured_data": {}
  },
  "signals": {
    "word_count":           1552,
    "reading_time":         7,
    "has_json_ld":          true,
    "heading_hierarchy_ok": true
  },
  "economics": {
    "raw_html_tokens_approx": 21331,
    "output_tokens_approx":   2715,
    "token_savings_percent":  0.873,
    "estimated_cost_usd": {
      "raw_html":   0.0640,
      "our_output": 0.0081,
      "savings":    0.0559
    }
  }
}
05

(Optional) Force a fresh fetch

Default behavior is cache-first: if the page is in our index and fresh enough, we serve from cache. To bypass the lookup and crawl now, set freshness_policy on the request body. The response echoes the policy back so your code can see exactly what happened.
curl -X POST https://api.lyrenth.com/v1/aidocument \
  -H "Authorization: Bearer $LYRENTH_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/post",
    "freshness_policy": "force_refresh"
  }'

# Response:
# "cache":  { "status": "refreshed", ... }
# "source": { "freshness_policy": "force_refresh", ... }

Allowed values for freshness_policy: cache_first (default) or force_refresh. Anything else is rejected with HTTP 400.

Beyond the basics

Other endpoints

The full surface is small on purpose. /v1/aidocument handles 95% of what an agent needs; the rest is mostly housekeeping.

POST/v1/aidocument

Resolve any URL

Body: { "url": "...", "freshness_policy"?: "cache_first"|"force_refresh" }. Cache on hit (free hits within the 90-day window), fresh fetch on miss, fetched body shared with every other caller. Counts as one request against your monthly quota.
GET/v1/document?url=...

Index lookup only

Returns the cached AIDocument if it's in our index, 404 otherwise. Never crawls. Useful for cheap dedupe / freshness checks without committing to a fetch. Counts as one request against your monthly quota.
POST/v1/submit

Queue a URL for indexing

Body: { "url": "..." }. Returns 202; we crawl in the background. Free (doesn't count toward quota) since nothing is returned synchronously.
GET/v1/quota

Your usage state

Returns this month's consumed-vs-limit shape. Free (housekeeping). The dashboard's sidebar progress card reads from this same endpoint.
GET/v1/stats

Public counter

Live count of indexed documents. No auth required; CORS-open. Useful for landing pages and embeds that want a fresh number.
GET/aidocument.schema.json

Machine-readable contract

The full v2 envelope as JSON Schema (draft-07). Validate responses, generate types, or point your editor at it as the source of truth. Mirrored at api.lyrenth.com/aidocument.schema.json.
Errors

What can go wrong

Errors are typed JSON; pattern-match on the error field rather than the HTTP status alone.

HTTP 429rate_limited

Per-key monthly quota reached. Response includes a Retry-After header pointing at the start of next month.

HTTP 502upstream_blocked

The target site's WAF / CDN rejected our crawler. Distinguish from generic upstream failures so your code can fall back gracefully.

HTTP 404not_indexed

On /v1/document only. The URL isn't in our cache. Hint suggests calling /v1/aidocument to resolve on demand.

HTTP 401unauthorized

Missing or invalid Bearer token. Verify $LYRENTH_KEY is set and the key isn't revoked.

Want the full document shape?

Every field in the response, what it contains, and the contract guarantees we make about backward compatibility.