Authentication and profile
57 routes. Paths are relative to https://api.intersink.com/v1.
- POST/auth/appleLogin with Apple (Sign in with Apple)
- POST/auth/googleLogin with Google (Sign in with Google)
- POST/auth/loginVerify OTP & Login
- POST/auth/login-appVerify OTP and Login (Mobile Apps)
- POST/auth/login-passwordLogin with email + password (OTP alternative)
- POST/auth/login-totpFinish a TOTP-protected login with an authenticator/backup code
- POST/auth/logoutLogout and revoke session
- GET/auth/meGet current user profile
- POST/auth/methodsWhich login methods an email supports (password/totp/otp/passkey)
- POST/auth/mfa/otpComplete login with the emailed OTP
- POST/auth/mfa/passkey/optionsSecond-factor passkey: get options
- POST/auth/mfa/passkey/verifySecond-factor passkey: verify and complete login
- POST/auth/mfa/totpComplete login with an authenticator/backup code
- POST/auth/opaque/credential/finishChange the password or recovery key, step 2
- POST/auth/opaque/credential/startChange the password or recovery key, step 1
- POST/auth/opaque/login/finishOPAQUE sign-in, step 2
- POST/auth/opaque/login/startOPAQUE sign-in, step 1
- POST/auth/opaque/register/finishOPAQUE signup, step 2: create the account
- POST/auth/opaque/register/startOPAQUE signup, step 1 (once per credential)
- POST/auth/passkey/login/optionsPasskey login, step 1: get options
- POST/auth/passkey/login/verifyPasskey login, step 2: verify the assertion and issue tokens
- POST/auth/passkey/register/optionsPasskey registration, step 1: get options
- POST/auth/passkey/register/verifyPasskey registration, step 2: verify and store
- GET/auth/passkeysList the signed-in user's passkeys
- DELETE/auth/passkeys/{id}Remove one of the signed-in user's passkeys
- GET/auth/powProof-of-work challenge for a new OPAQUE account
- PATCH/auth/profileUpdate user profile details
- GET/auth/recovery-codesHow many unused recovery codes remain (never the codes)
- POST/auth/recovery-codesReplace all recovery codes (needs a current authenticator code). The new codes are returned once.
- POST/auth/refreshRefresh authentication tokens (Web)
- POST/auth/refresh-appRefresh authentication tokens (Mobile Apps)
- POST/auth/request-otpRequest 6-digit OTP (Login/Register)
- POST/auth/reset-passwordReset password using an OTP (forgot password)
- GET/auth/security/activityThe signed-in user's security log: sign-ins, failed attempts, password / two-factor / passkey changes, session sign-outs (paged, max 100)
- GET/auth/security/summaryWhat protects the signed-in account: password set/changed, two-step methods, passkey and recovery-code counts (flags only)
- GET/auth/sessionsList all active sessions
- POST/auth/sessions/{id}/revokeRevoke a specific session
- POST/auth/sessions/logout-allSign out everywhere: revoke every session and refresh token except this one (step-up)
- POST/auth/sessions/revoke-allSign out everywhere: revoke every session and refresh token except this one (step-up)
- GET/auth/sign-in-optionsPublic: the bot check and sender address for a channel's sign-in pages
- GET/auth/step-upWhether this session has confirmed it's you in the last 10 minutes, and the ways it can
- POST/auth/step-upConfirm it's you (passkey, authenticator, password or e-mailed code); lasts 10 minutes for this session
- POST/auth/step-up/emailE-mail a 6-digit confirmation code to the account's own address
- POST/auth/step-up/endEnd the confirmation early
- POST/auth/step-up/opaque/finishConfirm it's you with the account's password (OPAQUE), step 2
- POST/auth/step-up/opaque/second-factorConfirm it's you with the password (OPAQUE), the second factor
- POST/auth/step-up/opaque/startConfirm it's you with the account's password (OPAQUE), step 1
- POST/auth/step-up/passkey/optionsPasskey challenge to confirm it's you
- POST/auth/switch-businessStage 2: Switch active profile/business and get new tokens (Web)
- POST/auth/switch-business-appStage 2: Switch active profile/business/channel (Mobile/CRM Apps)
- POST/auth/switch-channelStage 2: Switch active profile/business/channel (Mobile/CRM Apps)
- POST/auth/switch-profileStage 2: Switch active profile/business and get new tokens (Web)
- POST/auth/switch-profile-appStage 2: Switch active profile/business/channel (Mobile/CRM Apps)
- POST/auth/totp/disableDisable authenticator (TOTP) two-factor
- POST/auth/totp/enableConfirm a code to enable TOTP; returns backup codes
- POST/auth/totp/setupStart authenticator (TOTP) setup; returns a QR code
- PATCH/auth/two-factorEnable/disable two-factor authentication
Login with Apple (Sign in with Apple)
POST/auth/apple
Public: no sign-in needed.
Client sends the Apple identity token; the server verifies it against Apple's public keys and logs the user in (creating the account on first sign-in). Returns the same { access_token, refresh_token, user } as OTP.
Parameters
| Name | Type | Description |
|---|---|---|
| x-ref | string, header | |
| x-install-id | string, header |
Request body application/json
| Field | Type | Description |
|---|---|---|
| identity_tokenrequired | string | The Apple identity token from Sign in with Apple Example: "eyJraWQiOi..." |
| channel_id | string | Example: "REF-A1" |
| device_id | string | Example: "iphone_15_pro" |
Response
200. The payload in data is not described in the spec yet. Login successful
Login with Google (Sign in with Google)
POST/auth/google
Public: no sign-in needed.
Client sends the Google ID token; the server verifies it with Google and logs the user in (creating the account on first sign-in). Returns the same { access_token, refresh_token, user } as OTP login.
Parameters
| Name | Type | Description |
|---|---|---|
| x-ref | string, header | |
| x-install-id | string, header |
Request body application/json
| Field | Type | Description |
|---|---|---|
| id_tokenrequired | string | The Google ID token obtained by the client from Google Sign-In Example: "eyJhbGciOi..." |
| channel_id | string | Example: "REF-A1" |
| device_id | string | Example: "iphone_15_pro" |
Response
200. The payload in data is not described in the spec yet. Login successful
Verify OTP & Login
POST/auth/login
Public: no sign-in needed.
Any code sent to this address on this channel in the last 15 minutes works (the newest first), once. A wrong code: 401 INVALID_CODE with attemptsLeft ("That code didn't match. 4 tries left."). The 5th wrong try burns the code: 429 TOO_MANY_ATTEMPTS without retryAfterSeconds, ask for a new code. More than 20 wrong codes in an hour for the address lock code checks: 429 TOO_MANY_ATTEMPTS with retryAfterSeconds and unlockAt. A used or replaced code: 401 CODE_EXPIRED.
Parameters
| Name | Type | Description |
|---|---|---|
| x-ref | string, header |
Request body application/json
| Field | Type | Description |
|---|---|---|
| emailrequired | string | Example: "user@example.com" |
| otprequired | string | At least 6 characters. Example: "123456" |
| device_id | string | Example: "iphone_15_pro" |
| channel_id | string | Example: "REF-A1" |
| restore_account | boolean | Restore a closed account during its 30-day grace window. Without it, signing in to a closed account answers 403 ACCOUNT_CLOSED. |
Response
200. The payload in data is not described in the spec yet. Login successful
Verify OTP and Login (Mobile Apps)
POST/auth/login-app
Public: no sign-in needed.
The app's twin of /auth/login: tokens come in the body. Send the channel's app key (X-App-Key) and X-Install-Id: a random id the app makes once per install (a UUID, or 16 to 64 random letters, digits, '-' or '_') and sends on every request. The session is then bound to that install, never to the IP or user agent: it survives Wi-Fi/cellular changes and OS updates, and its tokens are refused (401 INSTALL_MISMATCH) from any other install. Without the header the session is bound to nothing. Two answers: a session (access_token, refresh_token, user), or, when the account has an authenticator or a 2-step passkey, mfa_required: true with methods and a 5-minute pending_token to finish at /auth/mfa/totp, /auth/mfa/otp or /auth/mfa/passkey/verify (send the same X-Install-Id there). Errors: 401 INVALID_CODE (with attemptsLeft), 401 CODE_EXPIRED, 429 TOO_MANY_ATTEMPTS, 403 ACCOUNT_CLOSED (restore with restore_account: true), 400 INVALID_INSTALL_ID.
Parameters
| Name | Type | Description |
|---|---|---|
| x-ref | string, header | |
| x-install-id | string, header |
Request body application/json
| Field | Type | Description |
|---|---|---|
| emailrequired | string | Example: "user@example.com" |
| otprequired | string | At least 6 characters. Example: "123456" |
| device_id | string | Example: "iphone_15_pro" |
| channel_id | string | Example: "REF-A1" |
| restore_account | boolean | Restore a closed account during its 30-day grace window. Without it, signing in to a closed account answers 403 ACCOUNT_CLOSED. |
Response
200. The payload in data is not described in the spec yet. A session, or a second step to finish
Login with email + password (OTP alternative)
POST/auth/login-password
Public: no sign-in needed.
Logs in with a password. If the account has a second factor enrolled, no tokens are returned yet: the response is { mfa_required: true, methods, pending_token } and the client finishes with /auth/mfa/totp, /auth/mfa/otp or /auth/mfa/passkey/verify.
Parameters
| Name | Type | Description |
|---|---|---|
| x-ref | string, header | |
| x-install-id | string, header |
Request body application/json
| Field | Type | Description |
|---|---|---|
| string | Email or username (one of the two is required) Example: "user@example.com" | |
| username | string | Sign in with the username of the account's profile in this channel. Example: "riya_716" |
| passwordrequired | string | Example: "MyS3cret!" |
| device_id | string | Example: "iphone_15_pro" |
| channel_id | string | Example: "REF-A1" |
| captcha | string | Cloudflare Turnstile token, when the channel turns the check on (GET /auth/sign-in-options) At most 2048 characters. |
Response
200. The payload in data is not described in the spec yet. Login successful or OTP required
Finish a TOTP-protected login with an authenticator/backup code
POST/auth/login-totp
Public: no sign-in needed.
Parameters
| Name | Type | Description |
|---|---|---|
| x-ref | string, header | |
| x-install-id | string, header |
Request body application/json
| Field | Type | Description |
|---|---|---|
| emailrequired | string | Example: "user@example.com" |
| coderequired | string | Authenticator or backup code Example: "123456" |
| device_id | string | Example: "iphone_15_pro" |
| channel_id | string | Example: "REF-A1" |
| captcha | string | Cloudflare Turnstile token (channels with auth.captcha=turnstile; see GET /auth/sign-in-options) At most 2048 characters. |
Response
200. The payload in data is of type object.
Logout and revoke session
POST/auth/logout
Needs a signed-in user (Bearer token or access_token cookie).
Response
200. The payload in data is not described in the spec yet. Logged out
Get current user profile
GET/auth/me
Needs a signed-in user (Bearer token or access_token cookie).
Response
200. The payload in data is not described in the spec yet. User profile returned
Which login methods an email supports (password/totp/otp/passkey)
POST/auth/methods
Public: no sign-in needed.
Parameters
| Name | Type | Description |
|---|---|---|
| x-ref | string, header |
Request body application/json
| Field | Type | Description |
|---|---|---|
| emailrequired | string | Example: "user@example.com" |
| channel_id | string | Example: "REF-A1" |
Response
200. The payload in data is not described in the spec yet.
Complete login with the emailed OTP
POST/auth/mfa/otp
Public: no sign-in needed.
Parameters
| Name | Type | Description |
|---|---|---|
| x-install-id | string, header |
Request body application/json
| Field | Type | Description |
|---|---|---|
| pending_tokenrequired | string | The pending-login token from the first factor |
| otprequired | string | The emailed OTP Example: "123456" |
Response
200. The payload in data is not described in the spec yet.
Second-factor passkey: get options
POST/auth/mfa/passkey/options
Public: no sign-in needed.
Parameters
| Name | Type | Description |
|---|---|---|
| x-install-id | string, header |
Request body application/json
| Field | Type | Description |
|---|---|---|
| pending_tokenrequired | string | The pending-login token from the first factor |
Response
200. The payload in data is of type object.
Second-factor passkey: verify and complete login
POST/auth/mfa/passkey/verify
Public: no sign-in needed.
Parameters
| Name | Type | Description |
|---|---|---|
| x-install-id | string, header |
Request body application/json
| Field | Type | Description |
|---|---|---|
| pending_tokenrequired | string | The pending-login token from the first factor |
| responserequired | object | The WebAuthn assertion response |
Response
200. The payload in data is not described in the spec yet.
Complete login with an authenticator/backup code
POST/auth/mfa/totp
Public: no sign-in needed.
Parameters
| Name | Type | Description |
|---|---|---|
| x-install-id | string, header |
Request body application/json
| Field | Type | Description |
|---|---|---|
| pending_tokenrequired | string | The pending-login token from the first factor |
| coderequired | string | Authenticator or backup code Example: "123456" |
Response
200. The payload in data is not described in the spec yet.
Change the password or recovery key, step 2
POST/auth/opaque/credential/finish
Needs a signed-in user (Bearer token or access_token cookie).
Stores the new record. Changing the password signs out every other session.
Request body application/json
| Field | Type | Description |
|---|---|---|
| credentialrequired | string | One of: "password", "recovery". |
| registration_recordrequired | string | At most 512 characters. |
Response
200. The payload in data is not described in the spec yet.
Change the password or recovery key, step 1
POST/auth/opaque/credential/start
Needs a signed-in user (Bearer token or access_token cookie).
Needs a recent sign-in (an OPAQUE sign-in counts for 10 minutes). Otherwise 401 STEP_UP_REQUIRED.
Request body application/json
| Field | Type | Description |
|---|---|---|
| credentialrequired | string | One of: "password", "recovery". |
| registration_requestrequired | string | At most 256 characters. |
Response
200. The payload in data is not described in the spec yet.
OPAQUE sign-in, step 2
POST/auth/opaque/login/finish
Public: no sign-in needed.
App tokens { account_id, access_token, refresh_token, expires_in } (rotate with /auth/refresh-app); 401 INVALID_CREDENTIALS. An enrolled authenticator or passkey still applies (mfa_required).
Parameters
| Name | Type | Description |
|---|---|---|
| x-ref | string, header |
Request body application/json
| Field | Type | Description |
|---|---|---|
| login_idrequired | string | At most 64 characters. |
| finish_login_requestrequired | string | OPAQUE KE3 / finishLoginRequest (base64url) At most 256 characters. |
| device_id | string | At most 255 characters. Example: "iphone-1" |
Response
200. The payload in data is of type object.
OPAQUE sign-in, step 1
POST/auth/opaque/login/start
Public: no sign-in needed.
credential = password | recovery. Unknown usernames get a well-formed fake response. 429 TOO_MANY_ATTEMPTS with retryAfterSeconds (and retry_after) after 10 failed sign-ins per username per hour.
Parameters
| Name | Type | Description |
|---|---|---|
| x-ref | string, header |
Request body application/json
| Field | Type | Description |
|---|---|---|
| usernamerequired | string | At most 64 characters. Example: "asha.07" |
| start_login_requestrequired | string | OPAQUE KE1 / startLoginRequest (base64url) At most 512 characters. |
| credentialrequired | string | One of: "password", "recovery". |
| captcha | string | Cloudflare Turnstile token (channels with auth.captcha=turnstile; see GET /auth/sign-in-options) At most 2048 characters. |
Response
200. The payload in data is not described in the spec yet.
OPAQUE signup, step 2: create the account
POST/auth/opaque/register/finish
Public: no sign-in needed.
Stores the password and recovery records and signs in. Needs a solved proof-of-work, a Turnstile token when the channel asks, and at most 5 new accounts per IP per day. QA mode (dev only): a .test email proven by its code from the test inbox makes a QA account, counted against the shared QA quota instead of the per-IP limit and purged after 7 days.
Parameters
| Name | Type | Description |
|---|---|---|
| x-ref | string, header |
Request body application/json
| Field | Type | Description |
|---|---|---|
| usernamerequired | string | At most 64 characters. Example: "asha.07" |
| registration_recordrequired | string | OPAQUE RegistrationRecord for the password At most 512 characters. |
| recovery_recordrequired | string | OPAQUE RegistrationRecord for the recovery key (mandatory) At most 512 characters. |
| powrequired | object | |
| pow.saltrequired | string | At most 64 characters. |
| pow.bitsrequired | number | |
| pow.exprequired | number | ms since epoch |
| pow.sigrequired | string | At most 128 characters. |
| pow.noncerequired | string | 1–64 chars of [A-Za-z0-9_-] At most 64 characters. |
| captcha | string | Cloudflare Turnstile token (channels with auth.captcha=turnstile) At most 2048 characters. |
| device | object | |
| device.device_id | string | At most 255 characters. Example: "iphone-1" |
| string | Optional email (recovery only). Needs email_otp from POST /auth/request-otp. Required when the channel keeps auth.email_required on. A .test address is accepted only on the dev API while QA mode is in effect (its code is read from the test inbox): the account is then tagged as a QA account, counts against the shared QA quota instead of SIGNUP_LIMIT and is purged after 7 days (docs/qa-mode.md). Elsewhere it is refused: 400 QA_EMAIL_REFUSED, or 503 QA_STORE_NOT_READY while QA mode waits for its tables. At most 254 characters. | |
| email_otp | string | Example: "123456" |
Response
200. The payload in data is not described in the spec yet. { account_id, access_token, refresh_token, expires_in }
OPAQUE signup, step 1 (once per credential)
POST/auth/opaque/register/start
Public: no sign-in needed.
Checks the username is free in the channel and answers the OPAQUE registration request. Call it twice with the same username: once for the password, once for the recovery key.
Parameters
| Name | Type | Description |
|---|---|---|
| x-ref | string, header |
Request body application/json
| Field | Type | Description |
|---|---|---|
| usernamerequired | string | 3–32 chars of [a-z0-9_.] with a letter (asha). The older form with '.' and a 2-digit discriminator (asha.07) is still accepted. Normalised to lowercase. At most 64 characters. Example: "asha" |
| registration_requestrequired | string | OPAQUE RegistrationRequest (base64url). Call once for the password and once for the recovery key. At most 256 characters. |
Response
200. The payload in data is not described in the spec yet.
Passkey login, step 1: get options
POST/auth/passkey/login/options
Public: no sign-in needed.
Parameters
| Name | Type | Description |
|---|---|---|
| x-ref | string, header |
Request body application/json
| Field | Type | Description |
|---|---|---|
| string | Omit for a discoverable (usernameless) passkey sign-in Example: "user@example.com" | |
| channel_id | string | Example: "REF-A1" |
Response
200. The payload in data is of type object.
Passkey login, step 2: verify the assertion and issue tokens
POST/auth/passkey/login/verify
Public: no sign-in needed.
Parameters
| Name | Type | Description |
|---|---|---|
| x-ref | string, header | |
| x-install-id | string, header |
Request body application/json
| Field | Type | Description |
|---|---|---|
| string | Example: "user@example.com" | |
| challenge_id | string | From passkey/login/options when no e-mail was given |
| responserequired | object | Assertion response from the authenticator |
| device_id | string | Example: "iphone_15_pro" |
| channel_id | string | Example: "REF-A1" |
Response
200. The payload in data is not described in the spec yet.
Passkey registration, step 1: get options
POST/auth/passkey/register/options
Needs a signed-in user (Bearer token or access_token cookie).
Response
200. The payload in data is not described in the spec yet.
Passkey registration, step 2: verify and store
POST/auth/passkey/register/verify
Needs a signed-in user (Bearer token or access_token cookie).
Request body application/json
| Field | Type | Description |
|---|---|---|
| responserequired | object | Attestation response from the authenticator |
| device_name | string | Example: "iPhone 15" |
Response
200. The payload in data is not described in the spec yet.
List the signed-in user's passkeys
GET/auth/passkeys
Needs a signed-in user (Bearer token or access_token cookie).
Response
200. The payload in data is not described in the spec yet.
Remove one of the signed-in user's passkeys
DELETE/auth/passkeys/{id}
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| idrequired | number, path |
Response
200. The payload in data is not described in the spec yet.
Proof-of-work challenge for a new OPAQUE account
GET/auth/pow
Public: no sign-in needed.
Stateless: { salt, bits, exp, sig }. Find a nonce so that sha256(salt ‖ nonce) has bits leading zero bits, then send { salt, bits, exp, sig, nonce } as pow to /auth/opaque/register/finish. Valid 10 minutes, one account per solution.
Response
200. The payload in data is of type object.
Update user profile details
PATCH/auth/profile
Needs a signed-in user (Bearer token or access_token cookie).
Request body application/json
| Field | Type | Description |
|---|---|---|
| firstname | string | At most 255 characters. |
| lastname | string | At most 255 characters. |
| username | string | At most 255 characters. |
Response
200. The payload in data is not described in the spec yet. Profile updated successfully
How many unused recovery codes remain (never the codes)
GET/auth/recovery-codes
Needs a signed-in user (Bearer token or access_token cookie).
Response
200. The payload in data is not described in the spec yet.
Replace all recovery codes (needs a current authenticator code). The new codes are returned once.
POST/auth/recovery-codes
Needs a signed-in user (Bearer token or access_token cookie).
Request body application/json
| Field | Type | Description |
|---|---|---|
| coderequired | string | Current authenticator code (or an unused recovery code) At most 32 characters. Example: "123456" |
Response
200. The payload in data is not described in the spec yet.
Refresh authentication tokens (Web)
POST/auth/refresh
Public: no sign-in needed.
Response
200. The payload in data is not described in the spec yet. New tokens issued
Refresh authentication tokens (Mobile Apps)
POST/auth/refresh-app
Public: no sign-in needed.
Trade the refresh token for a new pair. Never bound to the IP or user agent. A session signed in with X-Install-Id needs that same header here (401 INSTALL_MISMATCH otherwise: sign in again, refreshing won't help). An older session refreshed with the header becomes bound to that install. 401 UNAUTHENTICATED: the refresh token is unknown, spent, revoked or older than 30 days.
Parameters
| Name | Type | Description |
|---|---|---|
| x-install-id | string, header |
Request body application/json
| Field | Type | Description |
|---|---|---|
| refresh_tokenrequired | string |
Response
200. data is object (RefreshResultDto). New tokens issued
| Field | Type | Description |
|---|---|---|
| access_tokenrequired | string | New access token (15 minutes) Example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI4ZDFmNmE3ZSJ9.c2lnbmF0dXJl" |
| refresh_tokenrequired | string | New refresh token: the one sent is spent (a repeat within 30 seconds returns this same pair) Example: "ib1.5e8f3c2a9b7d4e6f1a0c8b2d4e6f8a1c3e5b7d9f1a3c5e7b9d1f3a5c7e9b1d3f.0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e" |
Request 6-digit OTP (Login/Register)
POST/auth/request-otp
Public: no sign-in needed.
Always answers 200 with the same body for any address: an unknown address, an existing account, an account with no saved mobile (delivery sms/whatsapp), a channel closed to new accounts and a blocked new address can't be told apart. A code is sent only when the address can sign in or sign up on this channel (signup policy, or a pending team invite there). The answer takes a minimum time (it follows the route's own speed) and does not wait for delivery. retryAfterSeconds says when Resend opens. Resend: 30 s after the first code, 60 s after the second, then 120 s, at most 5 codes per address and channel in 15 minutes (429 OTP_RATE_LIMIT_REACHED, reason cooldown or window). Every code sent stays valid for 15 minutes. Wider caps: per address across all channels (429 OTP_RECIPIENT_LIMIT), per IP, IPv6 by /64 network (429 OTP_IP_LIMIT) and per channel (429 OTP_CHANNEL_LIMIT). Every 429 carries the exact retryAfterSeconds and a Retry-After header. Parallel requests can't overshoot any of them.
Parameters
| Name | Type | Description |
|---|---|---|
| x-ref | string, header |
Request body application/json
| Field | Type | Description |
|---|---|---|
| emailrequired | string | Example: "user@example.com" |
| channel_id | string | Example: "REF-A1" |
| delivery | string | How to deliver the OTP. Defaults to "email". "sms"/"whatsapp" (worldwide via Twilio) are only for existing accounts and always go to the mobile stored on the account. SMS/WhatsApp are for account security only. One of: "email", "sms", "whatsapp". Example: "sms" |
| mobile | string | Ignored for OTP delivery: SMS/WhatsApp always go to the account's stored mobile. Example: "+919876543210" |
| captcha | string | Cloudflare Turnstile token, when the channel turns the check on (GET /auth/sign-in-options) At most 2048 characters. |
Response
200. data is object (RequestOtpResultDto). Accepted. message is the same for every address; a code was sent if the address can sign in here.
| Field | Type | Description |
|---|---|---|
| messagerequired | string | Example: "If this address can sign in here, a code is on its way." |
| emailrequired | string | Example: "user@example.com" |
| deliveryrequired | string | One of: "email", "sms", "whatsapp". |
| retryAfterSecondsrequired | number | Seconds until another code can be asked for (30 after the first, 60 after the second, then 120). Show it as a countdown on Resend. Example: 30 |
| expiresInSecondsrequired | number | How long this code works. Every code sent stays valid until its own expiry. Example: 900 |
| codeLengthrequired | number | Example: 6 |
Reset password using an OTP (forgot password)
POST/auth/reset-password
Public: no sign-in needed.
No current password needed. First call request-otp, then submit the code here with the new password.
Parameters
| Name | Type | Description |
|---|---|---|
| x-ref | string, header |
Request body application/json
| Field | Type | Description |
|---|---|---|
| emailrequired | string | Example: "user@example.com" |
| otprequired | string | At least 6 characters. Example: "123456" |
| new_passwordrequired | string | Example: "MyNewS3cret!" |
| channel_id | string | Example: "REF-A1" |
Response
200. The payload in data is not described in the spec yet. Password reset successfully
The signed-in user's security log: sign-ins, failed attempts, password / two-factor / passkey changes, session sign-outs (paged, max 100)
GET/auth/security/activity
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| page | number, query | Minimum 1. Example: 1 |
| limit | number, query | Max 100 Minimum 1. Example: 25 |
| category | string, query | One of: "sign_in", "session", "account", "mfa", "privacy", "vault". |
Response
200. The payload in data is not described in the spec yet.
What protects the signed-in account: password set/changed, two-step methods, passkey and recovery-code counts (flags only)
GET/auth/security/summary
Needs a signed-in user (Bearer token or access_token cookie).
Response
200. The payload in data is not described in the spec yet.
List all active sessions
GET/auth/sessions
Needs a signed-in user (Bearer token or access_token cookie).
Response
200. data is object[].
Revoke a specific session
POST/auth/sessions/{id}/revoke
Needs a signed-in user (Bearer token or access_token cookie).
Parameters
| Name | Type | Description |
|---|---|---|
| idrequired | string, path |
Response
201. The payload in data is not described in the spec yet.
Sign out everywhere: revoke every session and refresh token except this one (step-up)
POST/auth/sessions/logout-all
Needs a signed-in user (Bearer token or access_token cookie).
Needs a step-up in the last 10 minutes (401 STEP_UP_REQUIRED until POST /auth/step-up). With linked_devices: true (alias e2ee_devices), every linked end-to-end-encrypted device of the account is removed too, except this session's own device; pending device-link tokens stop working. The devices of the revoked sessions stop getting push notifications. revoked_sessions counts only the sessions this call deleted (one removed by a refresh while it runs is skipped). Any value of linked_devices other than a boolean form is 400 VALIDATION_FAILED. A row that cannot be deleted gives 503 SIGN_OUT_INCOMPLETE (send it again).
Request body application/json
| Field | Type | Description |
|---|---|---|
| linked_devices | boolean | Also remove every linked end-to-end-encrypted device of the account (except this session's own device). Default false. |
| e2ee_devices | boolean | Same as linked_devices. |
Response
200. The payload in data is not described in the spec yet.
Sign out everywhere: revoke every session and refresh token except this one (step-up)
POST/auth/sessions/revoke-all
Needs a signed-in user (Bearer token or access_token cookie).
Needs a step-up in the last 10 minutes (401 STEP_UP_REQUIRED until POST /auth/step-up). With linked_devices: true (alias e2ee_devices), every linked end-to-end-encrypted device of the account is removed too, except this session's own device; pending device-link tokens stop working. The devices of the revoked sessions stop getting push notifications. revoked_sessions counts only the sessions this call deleted (one removed by a refresh while it runs is skipped). Any value of linked_devices other than a boolean form is 400 VALIDATION_FAILED. A row that cannot be deleted gives 503 SIGN_OUT_INCOMPLETE (send it again).
Request body application/json
| Field | Type | Description |
|---|---|---|
| linked_devices | boolean | Also remove every linked end-to-end-encrypted device of the account (except this session's own device). Default false. |
| e2ee_devices | boolean | Same as linked_devices. |
Response
200. The payload in data is not described in the spec yet.
Public: the bot check and sender address for a channel's sign-in pages
GET/auth/sign-in-options
Public: no sign-in needed.
Send the channel as x-ref. captcha is { provider: 'none' } or { provider: 'turnstile', sitekey }. When it is Turnstile, request-otp, login-password, login-totp and opaque/login/start need the widget's token as captcha. sender is the address sign-in codes come from.
Parameters
| Name | Type | Description |
|---|---|---|
| x-ref | string, header |
Response
200. The payload in data is not described in the spec yet.
Whether this session has confirmed it's you in the last 10 minutes, and the ways it can
GET/auth/step-up
Needs a signed-in user (Bearer token or access_token cookie).
Response
200. The payload in data is not described in the spec yet.
Confirm it's you (passkey, authenticator, password or e-mailed code); lasts 10 minutes for this session
POST/auth/step-up
Needs a signed-in user (Bearer token or access_token cookie).
Request body application/json
| Field | Type | Description |
|---|---|---|
| methodrequired | string | One of: "passkey", "totp", "password", "email". |
| code | string | Authenticator, recovery or e-mailed code At most 32 characters. |
| password | string | At most 256 characters. |
| response | object | The passkey assertion (WebAuthn response JSON) |
Response
200. The payload in data is not described in the spec yet.
E-mail a 6-digit confirmation code to the account's own address
POST/auth/step-up/email
Needs a signed-in user (Bearer token or access_token cookie).
Response
200. The payload in data is not described in the spec yet.
End the confirmation early
POST/auth/step-up/end
Needs a signed-in user (Bearer token or access_token cookie).
Response
200. The payload in data is not described in the spec yet.
Confirm it's you with the account's password (OPAQUE), step 2
POST/auth/step-up/opaque/finish
Needs a signed-in user (Bearer token or access_token cookie).
Steps up THIS session for 10 minutes, as every step-up method does, and answers the GET /auth/step-up status. No new session and no tokens. If the account has an authenticator, passkey or e-mail codes, nothing is granted yet: the answer is { active: false, mfa_required: true, methods, expires_in: 300 } and the client finishes at /auth/step-up/opaque/second-factor. 401 INVALID_CREDENTIALS for a wrong password and for an expired, used or foreign login_id; 429 TOO_MANY_ATTEMPTS. Recorded as step_up_opaque (failures as step_up_failed, or login_locked at the limit).
Request body application/json
| Field | Type | Description |
|---|---|---|
| login_idrequired | string | login_id from /auth/step-up/opaque/start At most 64 characters. |
| finish_login_requestrequired | string | OPAQUE KE3 / finishLoginRequest (base64url) At most 256 characters. |
Response
200. The payload in data is of type object.
Confirm it's you with the password (OPAQUE), the second factor
POST/auth/step-up/opaque/second-factor
Needs a signed-in user (Bearer token or access_token cookie).
Only after /auth/step-up/opaque/finish answered mfa_required, within 5 minutes, on the same session and client. method = one of its methods: totp (authenticator or recovery code), passkey (assertion for POST /auth/step-up/passkey/options) or email (code from POST /auth/step-up/email). A wrong code can be retried until the step-up lockout; success steps up this session for 10 minutes, once. Errors as at /auth/mfa/*: 401 INVALID_CODE, INVALID_CREDENTIALS (passkey, other client), CODE_EXPIRED (nothing pending, or already used), 400 FACTOR_NOT_AVAILABLE, 429 TOO_MANY_ATTEMPTS.
Request body application/json
| Field | Type | Description |
|---|---|---|
| methodrequired | string | One of the methods the finish step answered. email: the code from POST /auth/step-up/email. passkey: the assertion for POST /auth/step-up/passkey/options. One of: "totp", "passkey", "email". |
| code | string | Authenticator code, recovery code or e-mailed code At most 32 characters. |
| response | object | The passkey assertion (WebAuthn response JSON) |
Response
200. The payload in data is not described in the spec yet.
Confirm it's you with the account's password (OPAQUE), step 1
POST/auth/step-up/opaque/start
Needs a signed-in user (Bearer token or access_token cookie).
The OPAQUE login exchange for the signed-in account (the username comes from the session, never the body). credential = password (default) | recovery. Answers { login_id, login_response }; login_id lives 2 minutes, works once, and only for this session from this client. The same lockout as sign-in: 429 TOO_MANY_ATTEMPTS after 10 failed tries an hour, sign-in and step-up together. 400 STEP_UP_METHOD_UNAVAILABLE when the account has no such credential; 404 METHOD_DISABLED when its channel turned OPAQUE off.
Request body application/json
| Field | Type | Description |
|---|---|---|
| start_login_requestrequired | string | OPAQUE KE1 / startLoginRequest (base64url) At most 512 characters. |
| credential | string | One of: "password", "recovery". |
Response
200. The payload in data is not described in the spec yet. { login_id, login_response }
Passkey challenge to confirm it's you
POST/auth/step-up/passkey/options
Needs a signed-in user (Bearer token or access_token cookie).
Response
200. The payload in data is of type object.
Stage 2: Switch active profile/business and get new tokens (Web)
POST/auth/switch-business
Needs a signed-in user (Bearer token or access_token cookie).
Request body application/json
| Field | Type | Description |
|---|---|---|
| profile_id | string | Example: "8b98f219-c120-4a8e-a9b0-4b2a8d1a1b1b" |
| business_id | string | Example: "5f3d06b8-3d46-4b0c-aae2-b443b2ea9973" |
| channel_id | string | Example: "42f5bb84-b9d6-41b9-b837-e9bba90ff03b" |
| refresh_token | string |
Response
201. The payload in data is not described in the spec yet.
Stage 2: Switch active profile/business/channel (Mobile/CRM Apps)
POST/auth/switch-business-app
Needs a signed-in user (Bearer token or access_token cookie).
Request body application/json
| Field | Type | Description |
|---|---|---|
| profile_id | string | Example: "8b98f219-c120-4a8e-a9b0-4b2a8d1a1b1b" |
| business_id | string | Example: "5f3d06b8-3d46-4b0c-aae2-b443b2ea9973" |
| channel_id | string | Example: "42f5bb84-b9d6-41b9-b837-e9bba90ff03b" |
| refresh_token | string |
Response
201. The payload in data is not described in the spec yet.
Stage 2: Switch active profile/business/channel (Mobile/CRM Apps)
POST/auth/switch-channel
Needs a signed-in user (Bearer token or access_token cookie).
Request body application/json
| Field | Type | Description |
|---|---|---|
| profile_id | string | Example: "8b98f219-c120-4a8e-a9b0-4b2a8d1a1b1b" |
| business_id | string | Example: "5f3d06b8-3d46-4b0c-aae2-b443b2ea9973" |
| channel_id | string | Example: "42f5bb84-b9d6-41b9-b837-e9bba90ff03b" |
| refresh_token | string |
Response
201. The payload in data is not described in the spec yet.
Stage 2: Switch active profile/business and get new tokens (Web)
POST/auth/switch-profile
Needs a signed-in user (Bearer token or access_token cookie).
Request body application/json
| Field | Type | Description |
|---|---|---|
| profile_id | string | Example: "8b98f219-c120-4a8e-a9b0-4b2a8d1a1b1b" |
| business_id | string | Example: "5f3d06b8-3d46-4b0c-aae2-b443b2ea9973" |
| channel_id | string | Example: "42f5bb84-b9d6-41b9-b837-e9bba90ff03b" |
| refresh_token | string |
Response
201. The payload in data is not described in the spec yet.
Stage 2: Switch active profile/business/channel (Mobile/CRM Apps)
POST/auth/switch-profile-app
Needs a signed-in user (Bearer token or access_token cookie).
Request body application/json
| Field | Type | Description |
|---|---|---|
| profile_id | string | Example: "8b98f219-c120-4a8e-a9b0-4b2a8d1a1b1b" |
| business_id | string | Example: "5f3d06b8-3d46-4b0c-aae2-b443b2ea9973" |
| channel_id | string | Example: "42f5bb84-b9d6-41b9-b837-e9bba90ff03b" |
| refresh_token | string |
Response
201. The payload in data is not described in the spec yet.
Disable authenticator (TOTP) two-factor
POST/auth/totp/disable
Needs a signed-in user (Bearer token or access_token cookie).
Request body application/json
| Field | Type | Description |
|---|---|---|
| coderequired | string | Code from authenticator app Example: "123456" |
Response
200. The payload in data is not described in the spec yet.
Confirm a code to enable TOTP; returns backup codes
POST/auth/totp/enable
Needs a signed-in user (Bearer token or access_token cookie).
Request body application/json
| Field | Type | Description |
|---|---|---|
| coderequired | string | Code from authenticator app Example: "123456" |
Response
200. The payload in data is not described in the spec yet.
Start authenticator (TOTP) setup; returns a QR code
POST/auth/totp/setup
Needs a signed-in user (Bearer token or access_token cookie).
Response
200. The payload in data is not described in the spec yet.
Enable/disable two-factor authentication
PATCH/auth/two-factor
Needs a signed-in user (Bearer token or access_token cookie).
Request body application/json
| Field | Type | Description |
|---|---|---|
| enabledrequired | boolean | Enable or disable 2FA Example: true |
Response
200. The payload in data is not described in the spec yet. Two-factor preference updated