Every API here is available over the APIs.io API and to AI agents over MCP.
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.'