MonetaryAI / Docs
API ReferenceAuthentication

Exchange credentials for a token pair

On the configured central host, email/password selects the oldest active membership. On tenant hosts, the tenant is taken from the host, not the body. A user of one tenant cannot authenticate against another tenant's subdomain. Repeated failures, from one address or against one account, are answered with 429 and Retry-After. When email 2FA is enabled, valid credentials without challengeId/code return 202 and queue an eight-digit code to the stored account email. Repeat this same login with password, challengeId and code to receive tokens. Codes expire in five minutes, permit five guesses and require provider acknowledgement. No tokens are issued at the challenge step. For Google Authenticator, 202 channel=TOTP requires repeating login with email, password and totpCode (six digits) or one unused recoveryCode. For TOTP, challengeId and expiresAt are null and no email is sent. On the second-factor submission, supply exactly one factor: paired email challengeId/code, totpCode, or recoveryCode; mixed factors return 400. A TOTP is accepted once across all memberships; wait for the next 30-second code after enrollment. Five Authenticator factor attempts per five minutes are permitted. The backend returns accessToken/refreshToken in the 200 JSON body, not browser cookies. The Next.js frontend BFF stores them in HttpOnly cookies and handles browser redirects; this backend endpoint does not redirect.

POST
/api/v1/auth/login

Request Body

application/json
  1. body

Start with email/password only. For a second factor, repeat email/password with paired challengeId/code OR totpCode OR recoveryCode. Factors are optional at the first step and mutually exclusive thereafter; mixed factors return 400.

challengeId?string

EMAIL only: challengeId from the 202 response; must be paired with code. Omit for TOTP/recovery.

Formatuuid
code?string

EMAIL only: eight-digit email code, paired with challengeId; expires in five minutes.

Match[0-9]{8}
email*string
Formatemail
Length1 <= length
password*string
Formatpassword
Length0 <= length <= 72
recoveryCode?string

TOTP only: one unused recovery code instead of totpCode; omit email factors.

Match(?i)[a-z2-7]{4}(?:-?[a-z2-7]{4}){3}
totpCode?string

TOTP only: fresh Google Authenticator six-digit code; omit all other factors.

Match[0-9]{6}

Response Body

Access and refresh tokens issued

application/json
  1. response
accessToken?string

Short-lived bearer JWT

refreshToken?string

One-time opaque refresh token

curl -X POST 'https://api.monetaryai.uz/api/v1/auth/login' \  -H 'Content-Type: application/json' \  -d '{  "email": "accountant@example.uz",  "password": "your-password"}'
{  "accessToken": "string",  "refreshToken": "string"}