Overview
This page hosts the interactive OpenAPI reference for the JSON API under /api/*. Endpoints still require authentication (session cookie,
portal session, API key where supported) and team-scoped authorization as documented per
operation.
The machine-readable spec is served at /openapi.json (redirects to the static build artifact). Use the sidebar to jump to rate limits, filter API sections, or open a tag group in the reference below.
Most JSON API routes under /api/* are throttled. When a limit is
hit, the server responds with 429 Too Many Requests, a JSON body that
includes retryAfter (seconds), and headers such as Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset. Retry after the indicated delay. Counters use
a rolling window (not fixed clock minutes).
How it is counted: most APIs use a per-IP bucket. For
signed-in staff on /api/* outside /api/portal/ and /api/auth/, a second per-user bucket applies (same numeric policies as below). Platform โview
asโ uses the operatorโs user id on /platform and /api/platform/*. Staff session requests to /api/portal/* use the IP bucket only (no per-staff-user bucket
on those routes). Client portal traffic on /api/portal/* is limited by IP in the hook, plus stricter per-portal-user caps on some writes (see below).
Shared office IP scaling: when several authenticated staff share one
external IP (same NAT), the per-IP limit for that route class increases โ
the routeโs base per-IP limit from the table below plus
150 requests/min per additional distinct
user active on that IP within the last 5 minutes
(global cap
2,500 / minute; scaled value is never below the route
base). Example: default /api/* at 7 users โ
500 / minute + 6ร150 =
1,400/min. Each user still has their own per-user bucket. Session
cookies, API keys, and assistant read tokens all count toward distinct users on the IP.
New trial teams: brand-new trialing firms use a lower default per-user API cap (2,000 / hour) until the team is established (paid subscription or 30+ days). Sign up is limited to 10 / hour per IP. Trusted production calibration firms (e.g. Utah Legal Group) and platform operators are exempt from trial-tier limits.
API keys and assistant read tokens: Bearer API key and assistant read JWT requests use the same route-class IP and per-user buckets as cookie sessions; there is no separate quota tier. Authenticated API key and assistant token traffic counts toward shared-IP scaling.
Not throttled by these rules: webhooks and similar callbacks, including /api/twilio/voice/*, /api/twilio/sms/*, /api/stripe/webhook, /api/webhooks/resend, /api/cron/*, and ONLYOFFICE document callback URLs.
Enforcement: when limits are on, counters are stored in Redis if both KV_REST_API_URL and KV_REST_API_TOKEN are set (recommended for production so all
instances share state). If Redis is unavailable or misconfigured, the server falls back to
an in-memory store for that process only. Local vite dev disables throttling unless RATE_LIMIT_ENABLED=true. Setting RATE_LIMIT_ENABLED=false turns limits off everywhere.
Per-route API buckets (IP / authenticated user)
| Area | Per IP | Per user (when logged in) |
|---|---|---|
Default /api/* (except auth) | 500 / minute | 10,000 / hour |
/api/twilio/* (REST, not webhooks) | 1,200 / minute | 12,000 / hour |
POST /api/templates/{id}/generate | 300 / minute | 3,000 / hour |
Document downloads (GET /api/documents/{id}/download, GET /api/documents/temp/โฆ), invoice PDF download | 1,500 / minute | 15,000 / hour |
/api/knowledge/* | 2,000 / minute | 20,000 / hour |
POST /api/assistant/chat | 60 / minute | 30 / minute |
Auth and portal (additional caps)
- Auth endpoints (sign-in, forgot password, reset password, portal
equivalents):
20 / 15 minutes / IP (shared
AUTHbucket). - Sign up: 10 / hour / IP (trial-tier signup protection).
- Portal magic link: 30 / 15 minutes / IP.
- Failed staff sign-in lockout: after repeated failures, the account can be temporarily locked (5 / 30 minutes, per identifier policy on the sign-in route).
- Portal writes: document uploads โ 40 / 15 minutes / portal user; portal messages โ 120 / 15 minutes / portal user.
Per-IP values in the table are base limits; shared NAT scaling may raise them (see above). /api/auth/* handlers apply their own IP-based policies (not the
global API hook). Team-switch routes are not throttled. Calibration baselines: see docs/RATE_LIMIT_BASELINES.md in the repo.