/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.
acceptedTermsmust be literallytrue(schemaconst) — 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 returns502with 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:
POST /2fa/setupwith{"setupToken"}→{"qrCode","manualKey","confirmToken"}.manualKeyis the base32 TOTP secret; standard RFC 6238, SHA-1, 6 digits, 30 s.POST /2fa/validate(the login second factor) with{"totpToken","code"}→200with the user object + session cookies.POST /2fa/verify-setupwith{"confirmToken","code":"123456"}→200with the user object, 10 single-use backup codes, and the session cookies. A malformed code returns400 {"ok":false,"error":{"code":"VALIDATION_ERROR","message":"body/code must match pattern \"^[0-9]{6}$\""}}.
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 /refreshrotates the pair (rate 10/min).POST /logoutrevokes every earlier token instantly.- CSRF: cookie-authenticated mutations require an
Origin(orReferer) header matching your dashboard origin, otherwise403 {"ok":false,"error":{"code":"CSRF_ORIGIN_MISMATCH","message":"Forbidden"}}. - Revocations (logout, password change, suspension, permission edits) take effect within seconds.
Account self-service (session required)
Password recovery (no session)
POST /forgot-passwordwith{"email"}— rate 3/15 min, always returns “success” (enumeration-safe). Sends a reset link with a 15-minute expiry.POST /reset-passwordwith{"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/lookupwith{"token"}(the 64-char emailed token) returns the accept-page metadata in the standard envelope:{ "ok": true, "data": { ... } }.POST /api/v1/team-invitations/acceptwith{"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: unlikeregisterandverify-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.