API overview¶
The JSON API lives under /api/v1/. Web pages (landing, upload, reports,
admin) are session-driven HTML and are not part of the versioned API surface.
Authentication¶
Sign-in is a magic link: you post your email, receive a single-use link that
expires in 15 minutes, and get a session cookie (HttpOnly, Secure,
SameSite=Lax). Consuming a link invalidates it and every earlier link for
that account. API calls authenticate with the session cookie. The admin panel
is separate, gated by an X-Admin-Token header, and returns 404 — not 401 —
when the token is absent or wrong.
Payment gate¶
One payment buys one audit credit; one upload consumes one credit atomically.
Uploading without an unconsumed credit returns 402 with payment links in the
response. Webhooks from the payment providers are HMAC-verified, checked
against a 5-minute timestamp tolerance, and deduplicated in an append-only
event table — a replayed webhook event can never grant a second credit.
Idempotency¶
POST /api/v1/audits honors the Idempotency-Key header: the first request
returns 201, an identical retry returns 200 with the same audit — safe to
retry on network failure without double-charging your credit.
Rate limits and queueing¶
Upload and auth endpoints are rate-limited per authenticated user where a
session exists, per IP otherwise; 429 responses carry Retry-After.
Current limits: POST /api/v1/audits 10/minute; magic-link and
early-access endpoints 5/minute. Processing has a concurrency cap: audits
beyond it hold in queued status and the status endpoint reports your
queue position.
Machine-readable spec¶
The live OpenAPI document is served at /openapi.json on the application
domain — generated from the running API, so it cannot drift from the
deployment.
Interactive API explorers and issued API keys arrive together (that surface
is trigger-registered: the first customer request for programmatic access).
Upload constraints¶
Files up to 200 MB; accepted formats are OpenAI JSONL, Anthropic JSONL, and the generic CSV contract. Format detection is per file; a file that parses as none of the three is rejected with a message telling you exactly what was expected.
Signed report URLs¶
Report links are signed and expire after 30 days. Tampered or expired tokens return 404 with no information about whether the audit exists.
Errors¶
Every /api/v1 error uses one envelope:
{
"error": {
"code": "payment_required",
"message": "This audit requires payment before processing.",
"request_id": "6d3f2c..."
}
}
| HTTP | code |
|---|---|
| 400 | bad_request |
| 401 | unauthorized |
| 402 | payment_required |
| 404 | not_found |
| 413 | payload_too_large |
| 422 | validation_error |
| 429 | rate_limited |
| 500 | internal_error |
request_id matches the server logs — include it when contacting support.
Error messages are user-safe by policy: parsing errors tell you what the
parser expected, never echo your data back.
The full endpoint list is generated from the code on every CI run.