Documentation

Getting started

  1. Create a free account.
  2. Create a key under Dashboard → API keys.
  3. Call an API:
curl "https://dev.itsozy.lol/api/v1/preview?url=https://example.com" \
  -H "Authorization: Bearer $OZY_KEY"

Authentication

API keys are bearer tokens beginning with ozy_. They are stored only as SHA-256 hashes and can be scoped to specific APIs. Account management endpoints (/api/v1/keys, /api/v1/account, /api/v1/usage, /api/v1/logs) require a signed-in browser session, not a key. Sessions use HttpOnly, Secure, SameSite=Strict cookies; state-changing session requests must come from this origin.

Rate limits and quotas

Per account20 units / minute, 100 units / day
Unit cost1 per call; 10 for OCR, screenshots and PDF parsing
Per hostoutbound requests to one host at least 1 s apart; robots.txt crawl-delay honoured (max 10 s)
Sign-in / registration15 attempts per 15 minutes per IP and per email
Resources10 API keys, 10 monitors, 10 saved extractions, 10 webhook relays, 2 active crawls
Payloadsrequest bodies 3 MiB; fetched pages 2 MiB; webhook payloads 256 KiB

Errors

All errors share {"error": {"code": "…", "message": "…"}} and a matching HTTP status. Messages never include stack traces or internal addresses. Every response carries an x-request-id.

OzyScrape and adaptive selectors

OzyScrape is an original Rust engine built on html5ever (via scraper). Rules accept CSS selectors or an XPath subset (//tag, //tag[@attr='v'], / child steps). Unsupported XPath fails explicitly rather than being reinterpreted.

With "adaptive": true, each exact match stores a fingerprint: tag, text, attributes, classes, six ancestors, neighbouring siblings, sibling pattern and position. If the selector later matches nothing, every element with the same tag is scored with a weighted similarity. A result is returned as recovered only when confidence ≥ 0.65 and it beats the runner-up by ≥ 0.07. Otherwise it is uncertain with an empty value list, and both numbers are reported.

Scrapling inspired the capability set. OzyScrape is an independent Rust implementation, and no Scrapling or Python code runs here. Benchmarks and methodology are in the repository's BENCHMARKS.md.

Security model

  • Only http/https on ports 80/443; no credentials in URLs.
  • Every DNS answer must be a public IPv4 address. The validated address is pinned into the connection, which defeats DNS rebinding.
  • Private, loopback, link-local, CGNAT, benchmark, documentation, multicast and cloud metadata ranges are blocked.
  • Redirects are followed manually (max 5), and each hop is re-validated.
  • Response bodies are streamed with a 2 MiB cap; the total time limit is 35 s.
  • Webhook destinations must be public HTTPS; redirects are never followed for deliveries.
  • Passwords use Argon2id. Webhook secrets are encrypted with AES-256-GCM.

Worker-backed APIs

Tesseract OCR and Chromium cannot run reliably inside Vercel functions. Those features use an optional, separately deployed Rust worker (crates/ozy-worker). The browser's traffic goes through the worker's own SSRF-filtering proxy. When no worker is configured, the affected endpoints return 503 worker_unavailable, and the status page says so.

Scheduling

Monitors, saved-extraction refreshes, webhook retries and queued crawls advance when the authenticated scheduler endpoint runs. Supabase pg_cron calls it every minute when configured, and a Vercel daily cron is the fallback. Check freshness on the status page.