امتثال
واجهة البرمجة

Auth

POST
/v1/auth/change-password

Rotate your own password. Requires the CURRENT password: a session alone is not sufficient, which is what stops a stolen token from being upgraded into a stolen credential. On success EVERY session is revoked -- including this one -- and outstanding access tokens are invalidated immediately, so the caller must log in again with the new password.

Authorization

BearerAuth
headerAuthorizationBearer <token>

JWT access token. Obtain via POST /v1/auth/login.

Request Body

application/json
  1. body

Authenticated password change. Identity comes from the SESSION, not the body.

There is deliberately no email field. The user is already authenticated, so accepting one would let a caller nominate an account other than their own — the endpoint would be an authorization bug wearing a form.

current_password*Current Password

The password being replaced. Verified before anything is written — this is what stops a stolen session token from being upgraded into a stolen credential.

Length1 <= length <= 128
new_password*New Password

New password (12-128 chars). Must use 3 of 4 character classes (lowercase, uppercase, digit, special) or be 16+ characters.

Length12 <= length <= 128

Response Body

Successful Response

application/json
  1. response
message?Message

Confirmation that the password changed and every refresh token was revoked. The caller's OWN session is revoked too — they cannot distinguish it from an attacker's.

Default"Password changed. All sessions were signed out, including this one; please log in with your new password."
curl -X POST 'https://api.aisc.sa/v1/auth/change-password' \  -H 'Content-Type: application/json' \  -d '{  "current_password": "string",  "new_password": "MyNewSecureP@ss123"}'
{  "message": "Password changed. All sessions were signed out, including this one; please log in with your new password."}
POST
/v1/auth/login

Log in with email and password. On success, returns access token (JWT, typically 1h TTL) and sets httpOnly refresh cookie (14 days, SameSite=Lax). Use access token in Authorization: Bearer header for subsequent requests. Refresh token binds to the issued access token (H-24 binding prevents token mixups).

Authorization

BearerAuth
headerAuthorizationBearer <token>

JWT access token. Obtain via POST /v1/auth/login.

Request Body

application/json
  1. body
email*Email

Registered email address.

Formatemail
password*Password

Account password.

Length1 <= length <= 128

Response Body

Successful Response

application/json
  1. response

Returned by login, verify-email, refresh — the full session envelope.

access_token*Access Token

JWT access token. Valid for ~1 hour. Include in Authorization: Bearer header.

email*Email

Authenticated user's email address.

expires_in*Expires In

Access token TTL in seconds from issue time.

telemetry_consent?|

The user's analytics consent, on login (spec C REQ-OBS-35); null on the other routes and when it could not be read.

tier*Tier

Subscription tier.

token_type?Token Type

Token type (always 'Bearer' for JWT).

Default"Bearer"
user_id*User Id

Authenticated user's UUID.

Formatuuid
curl -X POST 'https://api.aisc.sa/v1/auth/login' \  -H 'Content-Type: application/json' \  -d '{  "email": "user@example.com",  "password": "MySecureP@ss123"}'
{  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",  "email": "user@example.com",  "expires_in": 3600,  "telemetry_consent": {    "effective_from": "2019-08-24T14:15:22Z",    "notice_version": "v1",    "state": "unset"  },  "tier": "free",  "token_type": "Bearer",  "user_id": "550e8400-e29b-41d4-a716-446655440000"}
POST
/v1/auth/logout

Invalidate the current session. The refresh token is revoked in Redis and the cookie is deleted. Subsequent API calls without a fresh access token will fail with 401. The access token itself remains valid until exp, but is typically discarded client-side.

Authorization

BearerAuth
headerAuthorizationBearer <token>

JWT access token. Obtain via POST /v1/auth/login.

emtithal_refresh?string|null

Response Body

Successful Response

curl -X POST 'https://api.aisc.sa/v1/auth/logout'
Empty
GET
/v1/auth/me

Return the authenticated user's profile (email, tier, language preference, status). Requires valid Authorization: Bearer access_token header.

Authorization

BearerAuth
headerAuthorizationBearer <token>

JWT access token. Obtain via POST /v1/auth/login.

Response Body

Successful Response

application/json
  1. response

GET /v1/auth/me — the current user's profile.

account_type?string|null
display_name?string|null
email*Email
eula_version_accepted?|

The EULA version the user last accepted (spec E REQ-30); null on PATCH, when the user has accepted none, and when it could not be read.

has_verified_email*Has Verified Email

Whether email is verified

is_org_bound*Is Org Bound

Created through an org invite (organization-only view)

phone?string|null
preferred_lang*Preferred Lang

ISO 639-1 language code

sector?string|null
status*Status

Account status

subscription_tier*Subscription Tier

Current subscription tier

user_id*User Id
Formatuuid
curl -X GET 'https://api.aisc.sa/v1/auth/me'
{  "account_type": "individual",  "display_name": "Yousef A.",  "email": "user@example.com",  "eula_version_accepted": "2.0-2026-10-11",  "has_verified_email": true,  "is_org_bound": false,  "phone": "+966501234567",  "preferred_lang": "en",  "sector": "architecture",  "status": "active",  "subscription_tier": "free",  "user_id": "550e8400-e29b-41d4-a716-446655440000"}
PATCH
/v1/auth/me

Partially update the authenticated user's profile. Only fields present in the request body are changed (display_name, phone, sector, preferred_lang); an explicit null clears a nullable field. Email, password and account_type are not updatable here. Returns the updated profile.

Authorization

BearerAuth
headerAuthorizationBearer <token>

JWT access token. Obtain via POST /v1/auth/login.

Request Body

application/json
  1. body

PATCH /v1/auth/me — partial profile update (F-022).

Only fields present in the request are updated; explicit null clears a nullable field. Email / password / account_type are NOT updatable here.

display_name?|null
phone?|null
preferred_lang?|null
sector?|null

Response Body

Successful Response

application/json
  1. response

GET /v1/auth/me — the current user's profile.

account_type?string|null
display_name?string|null
email*Email
eula_version_accepted?|

The EULA version the user last accepted (spec E REQ-30); null on PATCH, when the user has accepted none, and when it could not be read.

has_verified_email*Has Verified Email

Whether email is verified

is_org_bound*Is Org Bound

Created through an org invite (organization-only view)

phone?string|null
preferred_lang*Preferred Lang

ISO 639-1 language code

sector?string|null
status*Status

Account status

subscription_tier*Subscription Tier

Current subscription tier

user_id*User Id
Formatuuid
curl -X PATCH 'https://api.aisc.sa/v1/auth/me' \  -H 'Content-Type: application/json' \  -d '{}'
{  "account_type": "individual",  "display_name": "Yousef A.",  "email": "user@example.com",  "eula_version_accepted": "2.0-2026-10-11",  "has_verified_email": true,  "is_org_bound": false,  "phone": "+966501234567",  "preferred_lang": "en",  "sector": "architecture",  "status": "active",  "subscription_tier": "free",  "user_id": "550e8400-e29b-41d4-a716-446655440000"}
POST
/v1/auth/refresh

Exchange the refresh cookie + current access token for a new access token pair. The refresh token is rotated on each call (H-24: binding to access_token.jti prevents reuse). Requires both the refresh cookie (httpOnly, sent automatically by the browser) and Authorization: Bearer header with the current access token (even if expired by exp claim). On refresh failure, the refresh cookie is cleared (user bounced to login).

Authorization

BearerAuth
headerAuthorizationBearer <token>

JWT access token. Obtain via POST /v1/auth/login.

emtithal_refresh?string|null

Response Body

Successful Response

application/json
  1. response

Returned by login, verify-email, refresh — the full session envelope.

access_token*Access Token

JWT access token. Valid for ~1 hour. Include in Authorization: Bearer header.

email*Email

Authenticated user's email address.

expires_in*Expires In

Access token TTL in seconds from issue time.

telemetry_consent?|

The user's analytics consent, on login (spec C REQ-OBS-35); null on the other routes and when it could not be read.

tier*Tier

Subscription tier.

token_type?Token Type

Token type (always 'Bearer' for JWT).

Default"Bearer"
user_id*User Id

Authenticated user's UUID.

Formatuuid
curl -X POST 'https://api.aisc.sa/v1/auth/refresh'
{  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",  "email": "user@example.com",  "expires_in": 3600,  "telemetry_consent": {    "effective_from": "2019-08-24T14:15:22Z",    "notice_version": "v1",    "state": "unset"  },  "tier": "free",  "token_type": "Bearer",  "user_id": "550e8400-e29b-41d4-a716-446655440000"}
POST
/v1/auth/register

Register a new user with email and password. A verification OTP is sent to the email; call POST /verify-email with the OTP to activate. Password must be 12+ characters, with complexity enforced (3 of 4 character classes or 16+ character passphrase).

Authorization

BearerAuth
headerAuthorizationBearer <token>

JWT access token. Obtain via POST /v1/auth/login.

Request Body

application/json
  1. body
account_type?|

Optional account type ('individual' or 'organization').

display_name?|

Optional display name.

email*Email

Email address for the new account. Must be unique.

Formatemail
eula_lang?|

Language of the EULA text the user accepted (spec E REQ-30).

eula_sha256*Eula Sha256

SHA-256 (64 hex chars) of the exact EULA document the user accepted.

Match^[a-fA-F0-9]{64}$
eula_version*Eula Version

Version identifier of the EULA the user accepted.

Lengthlength <= 20
password*Password

Password (12-128 chars). Must use 3 of 4 character classes (lowercase, uppercase, digit, special) or be 16+ characters long.

Length12 <= length <= 128
phone?|

Optional phone number.

preferred_lang?Preferred Lang

Preferred language. Must be 'ar' or 'en'. Defaults to 'en'. Used for error messages and email templates.

Default"en"
Value in"ar""en"
sector?|

Optional industry sector.

telemetry_consent?|

The analytics choice made on the consent banner before signing up, if any.

Response Body

Successful Response

application/json
  1. response
message?Message

User-facing message indicating next step (email verification).

Default"Verification email sent. Check your inbox."
user_id*User Id

UUID of the new user account.

Formatuuid
curl -X POST 'https://api.aisc.sa/v1/auth/register' \  -H 'Content-Type: application/json' \  -d '{  "email": "user@example.com",  "eula_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",  "eula_version": "2026-06-01",  "password": "MySecureP@ss123"}'
{  "message": "Verification email sent. Check your inbox.",  "user_id": "550e8400-e29b-41d4-a716-446655440000"}
POST
/v1/auth/request-password-reset

Send a 6-digit password-reset code to the given email. The response is DELIBERATELY identical whether or not the email is registered — this endpoint cannot be used to discover which addresses have accounts. Call POST /reset-password with the code to complete.

Authorization

BearerAuth
headerAuthorizationBearer <token>

JWT access token. Obtain via POST /v1/auth/login.

Request Body

application/json
  1. body
email*Email

Email address of the account to reset. The response is deliberately identical whether or not this email is registered (no account-existence disclosure).

Formatemail

Response Body

Successful Response

application/json
  1. response
message?Message

Generic, non-enumerable confirmation. Always returned regardless of whether the email exists.

Default"If that email is registered, a reset code has been sent."
curl -X POST 'https://api.aisc.sa/v1/auth/request-password-reset' \  -H 'Content-Type: application/json' \  -d '{  "email": "user@example.com"}'
{  "message": "If that email is registered, a reset code has been sent."}
POST
/v1/auth/resend-verification

Re-send the 6-digit signup OTP to the given email. The response is DELIBERATELY identical whether or not the email has a pending registration — this endpoint cannot be used to discover which addresses have accounts. Only accounts still awaiting email verification receive a new code.

Authorization

BearerAuth
headerAuthorizationBearer <token>

JWT access token. Obtain via POST /v1/auth/login.

Request Body

application/json
  1. body
email*Email

Email address to re-send the signup OTP to. The response is deliberately identical whether or not this email is registered / pending (no account-existence disclosure).

Formatemail

Response Body

Successful Response

application/json
  1. response
message?Message

Generic, non-enumerable confirmation. Always returned.

Default"If that email has a pending registration, a new code has been sent."
curl -X POST 'https://api.aisc.sa/v1/auth/resend-verification' \  -H 'Content-Type: application/json' \  -d '{  "email": "user@example.com"}'
{  "message": "If that email has a pending registration, a new code has been sent."}
POST
/v1/auth/reset-password

Set a new password using the 6-digit code from POST /request-password-reset. On success the password is changed and ALL existing sessions are revoked (the user must log in again). Errors are generic (no account-existence disclosure).

Authorization

BearerAuth
headerAuthorizationBearer <token>

JWT access token. Obtain via POST /v1/auth/login.

Request Body

application/json
  1. body
email*Email

Email address the reset code was requested for.

Formatemail
new_password*New Password

New password (12-128 chars). Must use 3 of 4 character classes (lowercase, uppercase, digit, special) or be 16+ characters.

Length12 <= length <= 128
otp*Otp

6-digit reset code sent to the email.

Match^\d{6}$
Length6 <= length <= 6

Response Body

Successful Response

application/json
  1. response
message?Message

Confirmation that the password changed and all refresh tokens were revoked. The user must log in again.

Default"Password reset. All existing sessions were signed out; please log in with your new password."
curl -X POST 'https://api.aisc.sa/v1/auth/reset-password' \  -H 'Content-Type: application/json' \  -d '{  "email": "user@example.com",  "new_password": "MyNewSecureP@ss123",  "otp": "123456"}'
{  "message": "Password reset. All existing sessions were signed out; please log in with your new password."}
POST
/v1/auth/verify-email

Complete email verification by submitting the 6-digit OTP sent to the registered email. On success, returns access token and sets httpOnly refresh cookie. The refresh token is bound to the access token (H-24 binding).

Authorization

BearerAuth
headerAuthorizationBearer <token>

JWT access token. Obtain via POST /v1/auth/login.

Request Body

application/json
  1. body

F-022: keyed by EITHER user_id (legacy) OR email — exactly one.

email?|

Registered email address. Supply exactly one of user_id / email.

marketing_email?Marketing Email

The unticked marketing-email box was ticked: consent to news and offers by email, recorded with the verification under the API's own wording version.

Defaultfalse
new_password*New Password

The account's password, chosen by whoever holds the inbox. Replaces any password given at registration. Same rules as registration.

Length12 <= length <= 128
otp*Otp

6-digit OTP sent to the registered email address.

Match^\d{6}$
Length6 <= length <= 6
user_id?|

UUID from the register response. Supply exactly one of user_id / email.

Response Body

Successful Response

application/json
  1. response

Returned by login, verify-email, refresh — the full session envelope.

access_token*Access Token

JWT access token. Valid for ~1 hour. Include in Authorization: Bearer header.

email*Email

Authenticated user's email address.

expires_in*Expires In

Access token TTL in seconds from issue time.

telemetry_consent?|

The user's analytics consent, on login (spec C REQ-OBS-35); null on the other routes and when it could not be read.

tier*Tier

Subscription tier.

token_type?Token Type

Token type (always 'Bearer' for JWT).

Default"Bearer"
user_id*User Id

Authenticated user's UUID.

Formatuuid
curl -X POST 'https://api.aisc.sa/v1/auth/verify-email' \  -H 'Content-Type: application/json' \  -d '{  "new_password": "MySecureP@ss123",  "otp": "123456"}'
{  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",  "email": "user@example.com",  "expires_in": 3600,  "telemetry_consent": {    "effective_from": "2019-08-24T14:15:22Z",    "notice_version": "v1",    "state": "unset"  },  "tier": "free",  "token_type": "Bearer",  "user_id": "550e8400-e29b-41d4-a716-446655440000"}