Programmatic surface.
The endpoints we'll keep stable across versions. Auth is the same session cookie the UI uses - sign in with curl + browser dev tools, or use one of the documented `Authorization` headers below.
Authentication
All endpoints below require an authenticated browser session via the authjs.session-token (or __Secure-authjs.session-token in production) cookie. The simplest way to use them from a script:
- Sign in via the browser at /signin.
- Copy the session cookie value from the dev tools.
- Send it with each request via
Cookie: authjs.session-token=….
The session cookie is httpOnly, so it cannot be accessed from page JavaScript - that's by design. There is no long-lived API token yet; if you have a use case that needs one, send us a note via our contact form.
CSRF
Any POST / PUT / PATCH / DELETE request must either have no Origin header (server-to-server) or carry an Origin that matches the deployment host. Cross-site origins are rejected with 403 forbidden at the middleware. Webhooks (/api/webhooks/*) are exempt because they authenticate via HMAC signature instead.
Account
POST /api/account/forgot-password
Trigger a password-reset email. Body { email: string }. Always returns 200 { ok: true, configured: boolean }enumeration-resistant. configured: false means email isn't wired on this deployment.
POST /api/account/reset-password
Consume a reset token. Body { token: string, password: string }. 200 on success, 410 when the token has expired, 409 when the token has already been consumed, 404 when unknown.
POST /api/account/change-password
Rotate password while signed in. Body { currentPassword, newPassword }. Returns 200 on success, 400 when the current password doesn't match, 409 for OAuth-only accounts (no password to change).
POST /api/account/verify-email/start
Re-send the email-verification link to the current user. Body empty. 200.
POST /api/account/verify-email/confirm
Consume a verification token. Body { token: string }. 200 / 410 / 409 / 404.
GET /api/account/export
GDPR data portability. Returns the signed-in user's full dataset as a single JSON file with Content-Disposition: attachment. Encrypted columns (Supabase keys, Postgres URL, TOTP secret) are excluded.
POST /api/account/2fa/{setup,enable,verify,disable}
The four-step 2FA lifecycle. See /settings/account/2fa for the wired UI; the API contracts are: setup returns a fresh secret + QR data URL; enable takes { secret, code } and persists; verify takes { code, recovery? } and sets the MFA cookie; disable takes { password } and clears.
Billing
POST /api/billing/checkout
Kick off a Dodo hosted checkout. Body empty. Returns { checkoutUrl: string }: the client navigates to it. 409 when the user already has an active subscription; 503 when billing isn't configured.
POST /api/billing/portal
Mint a Dodo customer-portal URL. Returns { url: string }. 404 when the user has no Dodo customer record yet.
POST /api/webhooks/dodo
Inbound Standard Webhooks endpoint. Verified by HMAC-SHA256 over `${webhook-id}.${webhook-timestamp}.${rawBody}` using DODO_WEBHOOK_SECRET. 5-minute replay tolerance. Idempotent via billing_event.webhook_id + applied_at.
Operational
GET /api/health
Liveness + readiness. Returns 200 when the database is reachable, 503 when not. Body shape:
{
"status": "ok" | "degraded",
"db": boolean,
"email": boolean,
"billing": boolean,
"observability": boolean,
"version": "3.x.y"
}POST /api/cron/retention
Manual trigger for audit-log + sentry-finding retention. Requires Authorization: Bearer <CRON_SECRET>. Returns the row counts pruned per table. Designed for cron-job.org / Coolify cron / GitHub Actions - not for in-app calls.
What's NOT public yet
The following exist and work, but their shape may change without notice - script against them at your own risk:
/api/v/<id>/*: the encrypted proxy. The contract follows PostgREST's under the hood, but our auth + filtering layer wraps it./api/connections/<id>/sentry/*: Agent Sentry scans + findings + quarantines./api/connections/<id>/sessions/*: agent sessions + one-click undo./api/connections/<id>/{widgets,actions,members}/*tied closely to the UI; expect shape changes./api/ai/*: AI chat conversations + analysis.
If you need a stable contract on any of these, let us know via our contact form - we'll publish it here once we know it's worth keeping stable.