POST /v1/read

Fetch any public URL and return clean Markdown plus extraction stats.

Cached for 1 hour per (URL, engine version). Set "fresh": true to bypass.

Endpoint

http
POST https://api.buildonto.dev/v1/read
Authorization: Bearer onto_sk_...
Content-Type: application/json

Request body

urlstringrequiredThe public URL to fetch and clean. Must be http:// or https://.
freshbooleanoptionalIf true, bypass the 1-hour cache and force a fresh fetch + extraction. Default: false.

Response

Success (200): JSON by default. Add Accept: text/markdown to get raw Markdown back instead.

json
{
  "status": "success",
  "url": "https://stripe.com",
  "markdown": "# Stripe — Online payments…\n\n…",
  "metadata": {
    "title": "Stripe | Financial Infrastructure...",
    "description": "Stripe powers online and...",
    "language": "en"
  },
  "stats": {
    "raw_html_size_kb": 605.0,
    "markdown_size_kb": 14.8,
    "reduction_percent": 97.6,
    "extraction_time_ms": 412
  },
  "cache": { "hit": false, "ttl_seconds": 3600 }
}

Errors: see error codes. Common ones for this endpoint: INVALID_URL (400), UNAUTHORIZED (401), ROBOTS_BLOCKED (403), WAF_BLOCKED (403), URL_NOT_FOUND (404), RATE_LIMITED (429), PAYMENT_REQUIRED (402), CONCURRENT_LIMIT (429), TIMEOUT (504).

Response headers

X-RateLimit-RemainingintoptionalPlan quota remaining for the current month.
X-RateLimit-ResetISO dateoptionalWhen the monthly counter resets (end of UTC month).
X-Onto-Billed'plan' | 'credit'optionalWhether this request hit your plan counter or debited a credit (overage).
X-Credits-RemainingintoptionalCredit balance after this request (only present when source='credit').
X-Concurrent-RemainingintoptionalHow many more in-flight requests you have headroom for at this moment.
X-Onto-Cache'HIT' | 'MISS'optionalWhether the response came from cache or a fresh fetch + extraction.

Examples

cURL — JSON response:

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

cURL — Markdown response (no JSON wrapper):

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

Node (fetch):

ts
const res = await fetch('https://api.buildonto.dev/v1/read', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.ONTO_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ url: 'https://stripe.com' }),
});
const data = await res.json();
console.log(data.markdown);

Python (httpx):

python
import os, httpx

r = httpx.post(
    "https://api.buildonto.dev/v1/read",
    headers={"Authorization": f"Bearer {os.environ['ONTO_API_KEY']}"},
    json={"url": "https://stripe.com"},
)
print(r.json()["markdown"])