Ethora Auth API

Authentication and session management.

GitHub OpenAPI

Operations 13

POST /v1/users/sign-up-with-email/ Users are allowed to register from the application, but they will need an… #
POST /v2/users/sign-up-with-email/ Users are allowed to register from the application, but they will need an… #
POST /v1/users/sign-up-resend-email/ if user do not receive the email, they can resend it #
POST /v1/users/login end user' login by google, facebook, apple, crypto' signature #
POST /v1/users/login-with-email login with email and password #
POST /v1/users/logout logout user #
POST /v1/users/set-permanent-password-with-temp-password set-permanent-password-with-temp-password #
POST /v1/users/login/refresh Refresh access token #
POST /v1/users/changePassword Change current user password #
POST /v1/users/verifyEmail Verify email address #
POST /v1/users/resendLink Resend verification link #
POST /v1/users/forgot Start forgot-password flow #
POST /v1/users/reset Reset password #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/ethora-com:ethora-com-auth-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

ethora-com-auth-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Platform Auth API
  description: 'Ethora Platform API.


    ## Getting Started

    - For new backend and tenant integrations, start with the `/v2/...` endpoints.

    - Use `/v2/apps/{appId}/...` when your backend/admin flow manages a specific target app explicitly.

    - Some legacy operations still exist only under `/v1/...`; when so, the operation description will say so.


    ## Integration Tracks

    - `Frontend / app runtime`: app-auth login/sign-up flows, then user-auth chats/files/sharelinks.

    - `Tenant admin / B2B backend`: explicit app management and app-scoped admin flows under `/v2/apps/{appId}/...`.


    ## Auth Token Legend

    - `App JWT`: app-scoped runtime token for sign-up/login/runtime app operations.

    - `User JWT`: end-user or admin-user session token.

    - `Refresh JWT`: refresh-only token for access token renewal.

    - `Client JWT`: legacy client-side token used only for chat/client credential exchange compatibility flows.

    - `B2B Server JWT`: tenant/backend integration token. Prefer `Authorization: Bearer `; `x-custom-token` is still accepted for backward compatibility.


    ## Which Token Where

    - `App JWT`: `/v1/users/login-with-email`, `/v2/users/sign-up-with-email`, similar app-runtime auth endpoints.

    - `User JWT`: user session endpoints like chats, files, sharelinks, profile/session management.

    - `B2B Server JWT`: tenant/backend integration endpoints, especially explicit `/v2/apps/{appId}/...` admin flows.

    - `Client JWT`: only where the endpoint explicitly says `Client JWT` and typically only for legacy compatibility.


    ## Auth Approach

    - `/v2/...` endpoints are the canonical API surface for new integrations.

    - Endpoints may support one or more token types depending on the actor and scope.

    - App-scoped admin/integration endpoints use `/v2/apps/{appId}/...` so the target app is always explicit.

    - When an endpoint supports both `User JWT` and `B2B Server JWT`, Swagger will show both under Security.

    - Public Swagger excludes internal-only, operational, and experimental surfaces.'
  contact:
    name: Dappros developers team
  version: 26.11.05
servers:
- url: https://api.chat.ethora.com
security:
- JwtAuth: []
tags:
- name: Auth
  description: Authentication and session management.
paths:
  /v1/users/sign-up-with-email/:
    post:
      summary: Users are allowed to register from the application, but they will need an…
      tags:
      - Auth
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  description: 'New account''s email address. Used for login, email

                    verification, and password reset.

                    '
                  type: string
                firstName:
                  description: 'Given name shown in chat / profile. Required.

                    '
                  type: string
                lastName:
                  description: 'Family name shown in chat / profile. Required.

                    '
                  type: string
                signupPlan:
                  description: 'Marketing plan tag captured at signup (`free`,

                    `business`, etc.). Free-form, used for analytics only.

                    '
                  type: string
                  enum:
                  - business
                  - free
                utm:
                  description: 'UTM-style attribution string captured at signup.

                    Free-form, used for analytics only.

                    '
                  type: string
                appId:
                  type: string
                  description: Application id used to resolve tenant/app context.
      responses:
        '200':
          description: "```\n{\n  ok: boolean,\n}\n```"
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          description: "```\n  { error: string }\n```"
        '500':
          $ref: '#/components/responses/InternalServerError'
      description: '**Auth**: None (appId required; legacy App JWT accepted)


        Provide `appId` in the request body to resolve app context. Legacy `Authorization` app token is also accepted for backward compatibility.'
      security: []
      operationId: post_v1_users_sign_up_with_email_
  /v2/users/sign-up-with-email/:
    post:
      summary: Users are allowed to register from the application, but they will need an…
      tags:
      - Auth
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  description: 'New account''s email address. Used for login, email

                    verification, and password reset.

                    '
                  type: string
                firstName:
                  description: 'Given name shown in chat / profile. Required.

                    '
                  type: string
                lastName:
                  description: 'Family name shown in chat / profile. Required.

                    '
                  type: string
                password:
                  description: 'Initial account password. 8+ characters recommended.

                    '
                  type: string
                cfToken:
                  description: 'Cloudflare Turnstile token from the sign-up form, if the

                    app has bot protection enabled. Optional otherwise.

                    '
                  type: string
                utm:
                  description: 'UTM-style attribution string captured at signup.

                    Free-form, used for analytics only.

                    '
                  type: string
                appId:
                  type: string
                  description: Application id used to resolve tenant/app context.
              required:
              - email
              - firstName
              - password
              - cfToken
      responses:
        '200':
          description: "```\n{\n  ok: boolean,\n}\n```"
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          description: "```\n  { error: string }\n```"
        '500':
          $ref: '#/components/responses/InternalServerError'
      description: '**Auth**: None (appId required; legacy App JWT accepted)


        Provide `appId` in the request body to resolve app context. Legacy `Authorization` app token is also accepted for backward compatibility.'
      security: []
      operationId: post_v2_users_sign_up_with_email_
  /v1/users/sign-up-resend-email/:
    post:
      summary: if user do not receive the email, they can resend it
      tags:
      - Auth
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  description: 'Email address that the verification link should be

                    re-sent to.

                    '
                  type: string
                appId:
                  type: string
                  description: Application id used to resolve tenant/app context.
      responses:
        '200':
          description: "```\n{\n  ok: boolean,\n}\n```"
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          description: "```\n  { error: string }\n```"
        '500':
          $ref: '#/components/responses/InternalServerError'
      description: '**Auth**: None (appId required; legacy App JWT accepted)


        Provide `appId` in the request body to resolve app context. Legacy `Authorization` app token is also accepted for backward compatibility.'
      security: []
      operationId: post_v1_users_sign_up_resend_email_
  /v1/users/login:
    post:
      summary: end user' login by google, facebook, apple, crypto' signature
      description: '**Auth**: None (appId required; legacy App JWT accepted)


        End user login endpoint, should be used with Authorization header set to App JWT.

        App JWT example: {JWT token}


        Provide `appId` in the request body to resolve app context. Legacy `Authorization` app token is also accepted for backward compatibility.'
      tags:
      - Auth
      requestBody:
        required: true
        content:
          application/json:
            schema:
              oneOf:
              - $ref: '#/components/schemas/UserGoogleAppleFacebookLogin'
              - $ref: '#/components/schemas/SignatureLogin'
            examples:
              social:
                value:
                  loginType: google | facebook | apple
                  password: pass
                  authToken: token
              signature:
                value:
                  loginType: signature
                  walletAddress: '0xd374e71b0943d2ca83968cb3c41332fc693a7427'
                  signature: '0xc83dcf6b475cf99026505658d87741ce9180cc0b4a4ab78d7044d3b9e9d3fdf153e3e9c9c549c06ca26581cdf5398b485129a64affdcc2357b4de68283fe4a541c'
                  msg: Login
      responses:
        '200':
          description: "```\n{\n  success: boolean,\n  user: {\n    defaultWallet: {\n      walletAddress: string\n    },\n    _id: string,\n    firstName: string,\n    lastName: string,\n    email: string,\n    username: string,\n    tags: string[],\n    profileImage: string,\n    emails: [\n      {\n        loginType: string,\n        email: string,\n        verified: boolean,\n        _id: string\n      }\n    ],\n    appId: string,\n    xmppPassword: string,\n    roles: string[],\n    isProfileOpen: boolean,\n    isAssetsOpen: boolean,\n    isAgreeWithTerms: boolean,\n    homeScreen: string,\n    registrationChannelType: string,\n    createdAt: string,\n    updatedAt: string\n  },\n  token: string,\n  refreshToken: string\n}\n```"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LoginSuccessResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: Not found
        '409':
          description: user did not validate his email in registration step
        '422':
          description: "```\n  { errors: [{msg: string}] }\n```"
        '500':
          $ref: '#/components/responses/InternalServerError'
      security: []
      operationId: post_v1_users_login
  /v1/users/login-with-email:
    post:
      summary: login with email and password
      description: '**Auth**: None (appId required; legacy App JWT accepted)


        End user login endpoint, should be used with Authorization header set to App JWT.

        Ethora App JWT example: JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7Il9pZCI6IjYxZTU1YzlkOTBlYTk5NTk0YmM3ZTZhMiIsImFwcE5hbWUiOiJFdGhvcmEiLCJhcHBHb29nbGVJZCI6Ijk3MjkzMzQ3MDA1NC1oYnNmMjlvaHBhdG83NnRpbDJqdGY2amdnMWI0Mzc0Yy5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsImNyZWF0b3JJZCI6IjYyYzNmNGE5M2FkMjcwNjc0YzFmNjJmYiIsImNyZWF0ZWRBdCI6IjIwMjItMDctMDVUMDg6Mjc6MjYuMzM2WiIsIl9fdiI6MH0sImlhdCI6MTY1NzAwOTY1OH0.dnvrO_dQ_2GLyUX-b71CcHFDnphpjeTYOxz6vZ2fsPY


        Provide `appId` in the request body to resolve app context. Legacy `Authorization` app token is also accepted for backward compatibility.'
      tags:
      - Auth
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  description: 'Account email address. Must match an existing user under

                    the calling app context.

                    '
                  type: string
                password:
                  description: 'Account password. 8+ characters in practice; weaker

                    passwords are rejected with `WRONG_CREDENTIALS`.

                    '
                  type: string
                appId:
                  type: string
                  description: Application id used to resolve tenant/app context.
      responses:
        '200':
          description: "```\n{\n  success: boolean,\n  user: {\n    defaultWallet: {\n      walletAddress: string\n    },\n    isSuperAdmin: {\n      read: boolean,\n      write: boolean\n    },\n    _id: string,\n    firstName: string,\n    lastName: string,\n    email: string,\n    username: string,\n    tags: string[],\n    profileImage: string,\n    emails: [\n      {\n        loginType: string,\n        email: string,\n        verified: boolean,\n        _id: string\n      }\n    ],\n    appId: string,\n    xmppPassword: string,\n    roles: string[],\n    isProfileOpen: boolean,\n    isAssetsOpen: boolean,\n    isAgreeWithTerms: boolean,\n    homeScreen: string,\n    registrationChannelType: string,\n    createdAt: string,\n    updatedAt: string\n  },\n  token: string,\n  refreshToken: string\n}\n```"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LoginSuccessResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          description: "```\n  { error: string }\n```"
        '500':
          $ref: '#/components/responses/InternalServerError'
      security: []
      operationId: post_v1_users_login_with_email
  /v1/users/logout:
    post:
      summary: logout user
      tags:
      - Auth
      parameters:
      - in: query
        name: type
        description: 'Optional logout scope: `current` (this session only, default) or

          `all` (every active session for this user).

          '
        schema:
          type: string
          enum:
          - all
          - current
          - except-current
      responses:
        '200':
          description: ok
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '500':
          $ref: '#/components/responses/InternalServerError'
      description: '**Auth**: User JWT'
      security:
      - UserJwtAuth: []
      operationId: post_v1_users_logout
  /v1/users/set-permanent-password-with-temp-password:
    post:
      summary: set-permanent-password-with-temp-password
      tags:
      - Auth
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                tempPassword:
                  description: 'One-time temporary password issued by the admin (e.g. via

                    batch user import).

                    '
                  type: string
                password:
                  description: 'New permanent password to set in place of the temporary

                    one.

                    '
                  type: string
      responses:
        '200':
          description: "```\n{\n  ok: boolean,\n}\n```"
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          description: "```\n{\n  error: string,\n}\n```"
        '500':
          $ref: '#/components/responses/InternalServerError'
      description: '**Auth**: None (temp password flow)'
      operationId: post_v1_users_set_permanent_password_with_temp_password
  /v1/users/login/refresh:
    post:
      description: '**Auth**: Refresh token (JWT)


        User refreshing'
      tags:
      - Auth
      responses:
        '200':
          description: "```\n{\n  token: string,\n  refreshToken: string\n}\n```"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AuthTokens'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
      - RefreshJwtAuth: []
      summary: Refresh access token
      operationId: post_v1_users_login_refresh
  /v1/users/changePassword:
    post:
      description: '**Auth**: User JWT


        Change the current user''s password. Pass `newPassword` (preferred);

        `npassword` is accepted as a deprecated alias for backward

        compatibility - if both are present, `newPassword` wins.'
      tags:
      - Auth
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - password
              properties:
                password:
                  description: 'Current account password.

                    '
                  type: string
                newPassword:
                  description: 'New password to set. 8+ characters recommended.

                    '
                  type: string
                npassword:
                  deprecated: true
                  description: '**Deprecated** - kept as a backward-compatible alias for

                    `newPassword`. New integrations should use `newPassword`.

                    If both are sent, `newPassword` wins.

                    '
                  type: string
      responses:
        '200':
          description: "```\n{\n  success: boolean,\n  msg: string\n} |\n{\n  success: false,\n  msg: 'Wrong Current Password'\n} |\n{\n  success: false,\n  errors: [{msg: string}]\n}\n```"
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
      - UserJwtAuth: []
      summary: Change current user password
      operationId: post_v1_users_changepassword
  /v1/users/verifyEmail:
    post:
      description: '**Auth**: User JWT


        Confirm the user''s email address from a verification link. Pass the

        `token` from the link; nothing else is read from the body.'
      tags:
      - Auth
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - token
              properties:
                token:
                  description: 'One-time email-verification token from the link sent at

                    sign-up (or via the resend endpoint). Single use; valid

                    for the lifetime stamped on the link.

                    '
                  type: string
      responses:
        '200':
          description: "```\n{\n  success: boolean,\n  msg: string\n}\n```"
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          description: "```\n{\n  errors: [{msg: string}]\n}\n```"
        '500':
          $ref: '#/components/responses/InternalServerError'
      security:
      - UserJwtAuth: []
      summary: Verify email address
      operationId: post_v1_users_verifyemail
  /v1/users/resendLink:
    post:
      description: '**Auth**: User JWT


        resend email verification link'
      tags:
      - Auth
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  description: 'Email address that the verification link should be

                    re-sent to.

                    '
                  type: string
      responses:
        '200':
          description: "```\n{\n  success: boolean,\n  msg: string\n}\n```"
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '500':
          description: "```\n{\n  error: string\n}\n```"
      security:
      - UserJwtAuth: []
      summary: Resend verification link
      operationId: post_v1_users_resendlink
  /v1/users/forgot:
    post:
      description: '**Auth**: None (appId required; legacy App JWT accepted)


        requests a password reset


        Provide `appId` in the request body to resolve app context. Legacy `Authorization` app token is also accepted for backward compatibility.'
      tags:
      - Auth
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  description: 'Email address to send the password-reset link to.

                    '
                  type: string
                appId:
                  type: string
                  description: Application id used to resolve tenant/app context.
      responses:
        '200':
          description: "```\n{\n  success: boolean,\n  msg: string\n}\n```"
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          description: "```\n{\n  error: string\n}\n```"
        '500':
          $ref: '#/components/responses/InternalServerError'
      security: []
      summary: Start forgot-password flow
      operationId: post_v1_users_forgot
  /v1/users/reset:
    post:
      description: '**Auth**: None (reset token in body)


        resets a user''s password'
      tags:
      - Auth
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                token:
                  description: 'One-time password-reset token from the email link. Valid

                    for 24h.

                    '
                  type: string
      responses:
        '200':
          description: "```\n{\n  ok: boolean,\n}\n```"
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          description: "```\n{\n  error: string\n}\n```"
        '500':
          description: "```\n{\n  error: string\n}\n```"
      security: []
      summary: Reset password
      operationId: post_v1_users_reset
components:
  responses:
    UnprocessableEntity:
      description: Unprocessable Entity
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    NotFound:
      description: Not Found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    BadRequest:
      description: Bad Request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    InternalServerError:
      description: Internal Server Error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Forbidden:
      description: Forbidden
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Unauthorized:
      description: Unauthorized
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
  schemas:
    SignatureLogin:
      type: object
      required:
      - walletAddress
      - signature
      - msg
      properties:
        walletAddress:
          type: string
        signature:
          type: string
        msg:
          type: string
    LoginSuccessResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        token:
          type: string
        refreshToken:
          type: string
        user:
          $ref: '#/components/schemas/UserPublic'
        isAllowedNewAppCreate:
          type:
          - boolean
          - 'null'
      required:
      - success
      - token
      - refreshToken
      - user
      additionalProperties: true
    UserPublic:
      type: object
      properties:
        _id:
          type: string
        uuid:
          type:
          - string
          - 'null'
        xmppUsername:
          type: string
        email:
          type:
          - string
          - 'null'
        firstName:
          type:
          - string
          - 'null'
        lastName:
          type:
          - string
          - 'null'
        username:
          type:
          - string
          - 'null'
        profileImage:
          type:
          - string
          - 'null'
        profilePicture:
          type:
          - string
          - 'null'
        description:
          type:
          - string
          - 'null'
        tags:
          type:
          - array
          - 'null'
          items:
            type: string
      additionalProperties: true
    UserGoogleAppleFacebookLogin:
      type: object
      required:
      - loginType
      - password
      - authToken
      properties:
        loginType:
          type: string
          enum:
          - google
          - facebook
          - apple
        authToken:
          type: string
        signupPlan:
          type: string
          enum:
          - business
          - free
        utm:
          type: string
    AuthTokens:
      type: object
      properties:
        token:
          type: string
          description: Access token (JWT / Bearer).
        refreshToken:
          type: string
      required:
      - token
      - refreshToken
    ErrorResponse:
      type: object
      properties:
        success:
          type: boolean
          description: Always false for error responses.
          example: false
        error:
          type: string
          description: A brief, human-readable message about the error.
        code:
          type: string
          description: A stable machine-readable error code.
          example: VALIDATION_ERROR
        details:
          type: object
          description: Optional, more specific details about the error (e.g., validation errors).
        errors:
          description: Legacy validation errors (if applicable).
        requestId:
          type: string
          description: Request correlation id for debugging/support.
      required:
      - error
      example:
        success: false
        error: Validation Failed
        code: VALIDATION_ERROR
        details:
          field: Reason
        requestId: '...'
  securitySchemes:
    JwtAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: 'Authorization: Bearer <JWT>'
    AppJwtAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: 'App JWT (data.type="app"). Use this token to call app-authorized endpoints (e.g. create user, login, signup). Authorization: Bearer <JWT>. Wrong token type returns code=INVALID_TOKEN_TYPE.'
    UserJwtAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: 'User JWT (data.type="user"). Use this token for user-authorized endpoints (e.g. chats/files/sharelinks/me). Authorization: Bearer <JWT>. Wrong token type returns code=INVALID_TOKEN_TYPE.'
    RefreshJwtAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: 'Refresh JWT (data.type="refresh"). Use this token only for refresh flow. Authorization: Bearer <JWT>. Wrong token type returns code=INVALID_TOKEN_TYPE.'
    ClientJwtAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: 'Client JWT (data.type="client"). Legacy compatibility token used only for client credential exchange endpoints. Preferred header: x-custom-token; Authorization Bearer may also be accepted by some deployments.'
    B2BServerJwtAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: 'B2B Server JWT (data.type="server"). Use this token for tenant/backend integration endpoints. Preferred header: Authorization: Bearer <JWT>. Legacy header x-custom-token is also accepted for backward compatibility.'