Request
Step 1 — Initialize login
login_token (valid for 3 minutes) that must be included in Step 2.
Response
Short-lived login token to include in the credential submission.
ISO 8601 expiration timestamp for the login token.
Step 2 — Submit credentials
The user’s email address.
The user’s password (minimum 8 characters).
The one-time token obtained from
POST /api/v1/auth/login/init.Identifier for the 2FA challenge. Pass this to Step 3.
The 2FA method issued:
totp or email_otp.ISO 8601 expiration timestamp for the challenge.
Whether the user may verify using a backup code.
Step 3 — Verify 2FA challenge
The challenge ID from Step 2.
The verification code (OTP, TOTP code, or backup code). Must be between 4 and 32 characters.
The type of code being submitted.
primary for OTP/TOTP, backup for a backup code.Short-lived JWT access token (valid for 15 minutes). Pass as
Authorization: Bearer <token> on authenticated requests.Long-lived refresh token (valid for 30 days). Use to obtain a new access token without re-authenticating.
Refresh tokens
Exchange an expired access token for a new pair without re-authenticating. The old refresh token is immediately revoked.A valid, unexpired refresh token.
New short-lived JWT access token.
New refresh token (the submitted token is revoked).
Logout
Authorization: Bearer <access_token> header.
The refresh token to revoke. Required when
logout_all_devices is false.When
true, all refresh tokens for the authenticated user are revoked across every device.true when logout completed successfully.Confirmation message.
Resend 2FA code
If the email OTP expires or is not delivered, resend it for an active challenge.The challenge ID from Step 2.
Error codes
| Status | Description |
|---|---|
400 | Missing or invalid fields, or invalid/expired login_token. |
401 | Invalid credentials. |
403 | Account locked after 5 failed attempts (locked for 6 hours), or email not verified. |
429 | Rate limit exceeded (3 attempts per minute per IP and email). |