How it works
The architecture under both products.
Onto has two delivery paths but one cleaning engine. The Read API serves AI developers fetching arbitrary URLs. The Serve SDK serves site owners who want their own pages to be agent-readable. Both produce the same kind of clean Markdown from the same underlying extractor.
Read API path
text
Agent / your code
│ POST /v1/read { url }
▼
api.buildonto.dev (Vercel)
│ 1. Authenticate Bearer token
│ 2. Check rate-limit + concurrency slot
│ 3. Hit cache (1h TTL)
│ ┌─ HIT → return cached payload
│ └─ MISS → continue
│ 4. Honor target's robots.txt (short-circuit if disallowed)
│ 5. Fetch target URL (10s timeout)
│ 6. Run @ontosdk/core extractor → clean Markdown
│ 7. Score (if /v1/score or /v1/read-and-score)
│ 8. Cache + log usage + return
▼
JSON or text/markdown responseServe SDK path
text
Build time (your CI):
next build → onto-next
↳ for each route, extract HTML → Markdown
↳ write public/.onto/{route}.md
↳ POST manifest to /api/files (so dashboard sees them)
Request time (your edge):
Bot request → @ontosdk/next middleware
↳ detect bot (UA or Accept)
↳ fetch /.onto/{route}.md (internal subrequest)
↳ POST /api/track (telemetry, fire-and-forget)
↳ GET /api/injections?route={path} (Pro+, append if found)
↳ return clean Markdown with X-Onto-* headers
Human request → middleware passes through, full HTML servedShared engine
Both paths run the same @ontosdk/core package (currently 0.1.0 on npm). The Read API runs it at request time on the URL the customer sends; the Serve SDK runs it at build time on the customer's own HTML output. Same cleaning rules, same heading hierarchy normalization, same scoring penalties.
@ontosdk/core
The extractor + scorer. Same engine drives both products.
@ontosdk/next
Build CLI + middleware specific to Next.js sites.
onto-api
The Read API service hosted at api.buildonto.dev.
Where data lives
| Data | Store | Purpose |
|---|---|---|
| API keys (hashed) | Supabase api_keys | Bearer auth for Read API |
| Per-site keys | Supabase sites | SDK auth for Serve |
| Per-route .md files | Supabase onto_files | Manifest the dashboard reads |
| Agent visit telemetry | Supabase agent_events | Drives /serve/analytics |
| Read API usage events | Supabase usage_events | Drives /read/usage + billing reconciliation |
| Monthly counter, concurrency | Vercel KV (Redis) | Hot-path rate limiting + cache |
| Cleaned Markdown cache | Vercel KV (1h TTL) | Avoid re-extraction on the Read API |
| Subscriptions + credits | Supabase subscriptions + profiles.credit_balance | Polar webhook syncs these |
Two products, two billing lines, one auth. A single signed-in user can hold one Read subscription AND one Serve subscription via the same Supabase auth — the
subscriptions table is keyed on (user_id, kind) where kind is read or serve.