Skip to main content
These endpoints power the dashboard. An API integration never needs them — it uses an API key. They matter to you if you automate onboarding or build tooling around a dashboard session. Two rules apply to everything under /api/v1/auth/*:
  • Rate limits are per IP — a client-supplied token cannot mint fresh buckets.
  • Responses are enumeration-safe: you cannot use them to find out whether an email is registered.

From registration to first login

1

Register

POST /register — rate 3/min.
Request body
  • Password policy: 8+ chars with mixed case, numbers and specials.
  • acceptedTerms must be literally true (schema const) — clickwrap consent is recorded (versions, timestamp, IP).
  • The response is normally 200 {"requiresVerification":true,"email":"..."} whether or not the email is already registered — the already-registered case short-circuits to the same 200 before any email is sent, so the two are indistinguishable (enumeration-safe). The one exception is a transport failure: if the account is newly created but the verification email cannot be sent, the endpoint returns 502 with a distinct body, so the identical-response guarantee holds only while email delivery is healthy.
2

Verify the email

POST /verify-email — rate 5/15 min.Send {"email":"...","code":"434300"}. The code is 6 digits, expires in 15 minutes, and is invalidated after 5 wrong guesses.Success: {"success":true,"message":"Email verified. You can now sign in."}. Every failure mode returns the same generic 400 {"error":"Invalid or expired verification code"}.Need a new code? POST /resend-verification with {"email"} — rate 3/15 min, always returns “success”.
3

Log in

POST /login — rate 5/min, body {"email","password"}. Possible outcomes:
4

Enroll TOTP (mandatory)

2FA enrollment is not optional. The flow:
  1. POST /2fa/setup with {"setupToken"} → {"qrCode","manualKey","confirmToken"}. manualKey is the base32 TOTP secret; standard RFC 6238, SHA-1, 6 digits, 30 s.
  2. POST /2fa/validate (the login second factor) with {"totpToken","code"} → 200 with the user object + session cookies.
  3. POST /2fa/verify-setup with {"confirmToken","code":"123456"} → 200 with the user object, 10 single-use backup codes, and the session cookies. A malformed code returns 400 {"ok":false,"error":{"code":"VALIDATION_ERROR","message":"body/code must match pattern \"^[0-9]{6}$\""}}.
Store the 10 single-use backup codes the moment POST /2fa/verify-setup returns them — they are shown only once.
Passkey alternative: POST /2fa/validate-passkey at login; /passkey/register-options + /passkey/register-verify to enroll from a session; /passkey/login-options + /passkey/login-verify for passwordless login.

Sessions: cookies, refresh, CSRF

  • A successful login sets secure httpOnly cookies: an access token (15 min) and a refresh token (7 days). The access token is also accepted as Authorization: Bearer <token>.
  • POST /refresh rotates the pair (rate 10/min). POST /logout revokes every earlier token instantly.
  • CSRF: cookie-authenticated mutations require an Origin (or Referer) header matching your dashboard origin, otherwise 403 {"ok":false,"error":{"code":"CSRF_ORIGIN_MISMATCH","message":"Forbidden"}}.
  • Revocations (logout, password change, suspension, permission edits) take effect within seconds.
Automating against a dashboard session? Send the access JWT as Authorization: Bearer <jwt> instead of relying on cookies — header-bearer callers are exempt from the CSRF origin check, because they carry no ambient cookie credential.

Account self-service (session required)

Password recovery (no session)

  • POST /forgot-password with {"email"} — rate 3/15 min, always returns “success” (enumeration-safe). Sends a reset link with a 15-minute expiry.
  • POST /reset-password with {"email","token","newPassword"} — rate 5/15 min. Resets the password and revokes all existing sessions.

Team invitations (public, token-credentialed)

  • POST /api/v1/team-invitations/lookup with {"token"} (the 64-char emailed token) returns the accept-page metadata in the standard envelope: { "ok": true, "data": { ... } }.
  • POST /api/v1/team-invitations/accept with {"token","password","displayName"} creates the member account and returns { "ok": true, "data": { "requiresTotpSetup": true, "setupToken": "..." } } — members must enroll 2FA before their first session, following the same enrollment flow shown above. Note the envelope: unlike register and verify-email (which return raw bodies), these two wrap their payload in {ok, data}.

Create an API key

Mint a lid_live_* secret key from the dashboard session you just established (MFA required).

API Overview

The three credential types, scopes, response envelopes, and rate limits.