Authentication

ZapTicket uses a two-level JWT flow. First authenticate as a user, then select a workspace to get a scoped workspace token.

Overview

Authentication in ZapTicket is a two-step process. When you register or log in, you receive a user token — this identifies you as a person but does not grant access to any workspace data. To interact with conversations, tickets, or settings, you must select a workspace which returns a workspace token scoped to that tenant.

💡All tokens are short-lived JWTs (1 hour expiry). The workspace token contains the tenant ID and agent role in its claims, which the backend uses for authorization and query filtering.

Token Flow

Authentication Flow
1. POST /auth/register  →  user token (no workspace context)
   OR
   POST /auth/login     →  user token (no workspace context)

2. GET /workspaces      →  list of workspaces user belongs to
                            (requires user token)

3. POST /workspaces/{id}/select  →  workspace token (scoped to tenant)
                                     (requires user token)

4. Use workspace token for all subsequent API calls
   Authorization: Bearer <workspace_token>

Endpoints

Register

POST/auth/register

Create a new user account. Returns a user-level JWT.

Auth: None

Request Body
{
  "email": "[email protected]",
  "password": "SecureP@ss123",
  "fullName": "Jane Smith"
}
Response 201
{
  "token": "eyJhbGciOiJIUzI1NiIs...",
  "user": {
    "id": "usr_abc123",
    "email": "[email protected]",
    "fullName": "Jane Smith",
    "emailVerified": false,
    "createdAt": "2024-01-15T10:30:00Z"
  }
}
⚠️If a user with the same email already exists, the API returns 409 Conflict with an error message. Passwords must be at least 8 characters with one uppercase, one lowercase, and one number.

Login

POST/auth/login

Authenticate with email and password. Returns a user-level JWT.

Auth: None

Request Body
{
  "email": "[email protected]",
  "password": "SecureP@ss123"
}
Response 200
{
  "token": "eyJhbGciOiJIUzI1NiIs...",
  "user": {
    "id": "usr_abc123",
    "email": "[email protected]",
    "fullName": "Jane Smith",
    "emailVerified": true,
    "createdAt": "2024-01-15T10:30:00Z"
  }
}

Returns 401 Unauthorized if credentials are invalid. The login endpoint is rate-limited to 10 attempts per 5 minutes per IP to prevent brute-force attacks.

Get Current User

GET/auth/me

Returns the authenticated user's profile and a list of workspaces they belong to.

Auth: User token or Workspace token

Response 200
{
  "id": "usr_abc123",
  "email": "[email protected]",
  "fullName": "Jane Smith",
  "emailVerified": true,
  "createdAt": "2024-01-15T10:30:00Z",
  "workspaces": [
    {
      "id": "ws_xyz789",
      "name": "Acme Inc",
      "slug": "acme-inc",
      "role": "admin"
    }
  ]
}

Verify Email

GET/auth/verify-email

Verify a user's email address using the token sent to their inbox.

Auth: None (token in query param)

Query Parameters
GET /auth/verify-email?token=eyJhbGciOiJIUzI1NiIs...
Response 200
{
  "message": "Email verified successfully"
}

Returns 400 Bad Request if the token is expired or invalid. Verification tokens expire after 24 hours, after which the user must request a new one.

Using Tokens

Include the JWT in the Authorization header for all authenticated requests:

Example Request
curl -X GET https://api.zapticket.app/conversations \
  -H "Authorization: Bearer <workspace_token>" \
  -H "Content-Type: application/json"
🚨Never expose tokens in client-side code or URLs. For widget authentication, use the site-key mechanism described in the Widget Endpoints docs.