Administration API

This article and the rest of the API documentation in this section are written for a technical audience — integrators and developers connecting external systems to Tickiti. Familiarity with HTTP, REST, JSON and bearer-token authentication is assumed.

The Administration API exposes the Administration screens — system settings, branding, custom domain, AI assistant, users & queue permissions, teams, API keys, licence status, storage management and diagnostics. Every endpoint runs as the token’s owner and is gated by the administration ability plus the owner’s admin role; a few are additionally restricted to sysadmin and keep their in-app password re-check.

Abilities and conventions

  1. administration:read — read endpoints.
  2. administration:write — create / update / action endpoints. Write implies read.

All endpoints are POST and JSON. Custom-domain and AI-assistant updates require the owner to be a sysadmin and to supply the operator’s current_password in the body, exactly as the screens do. Reads never return secrets (the AI key, mailbox passwords, remote tokens). The registration eligibility service token is write-only: the system settings return only registration_eligibility_token_set, true when one is stored. Seat limits and the sysadmin-only role flags on user changes are enforced as in the UI.

Endpoints

Method & pathAbilityPurpose
POST /api/v1/administration/systemadministration:readSystem settings
POST /api/v1/administration/system/updateadministration:writeUpdate system options
POST /api/v1/administration/brandingadministration:readBranding settings
POST /api/v1/administration/branding/updateadministration:writeUpdate branding (names, colours, logo sizes)
POST /api/v1/administration/branding/app-logoadministration:writeUpload the app logo (multipart)
POST /api/v1/administration/branding/email-logoadministration:writeUpload the email logo (multipart)
POST /api/v1/administration/branding/reset-app-logoadministration:writeReset the app logo
POST /api/v1/administration/branding/reset-email-logoadministration:writeReset the email logo
POST /api/v1/administration/custom-domainadministration:read (sysadmin)Custom-domain state
POST /api/v1/administration/custom-domain/updateadministration:write (sysadmin + password)Set the custom domain
POST /api/v1/administration/ai-assistantadministration:read (sysadmin)AI-assistant settings/stats
POST /api/v1/administration/ai-assistant/updateadministration:write (sysadmin + password)Update AI-assistant settings
POST /api/v1/administration/usersadministration:readList users + queues
POST /api/v1/administration/users/createadministration:writeCreate a user (seat-limited)
POST /api/v1/administration/users/{user}/updateadministration:writeUpdate a user’s roles and settings
POST /api/v1/administration/users/{user}/queues/{queue}administration:writeUpsert a queue permission
POST /api/v1/administration/users/{user}/queues/{queue}/detachadministration:writeRemove a queue permission
POST /api/v1/administration/teamsadministration:readList teams, their members and what uses them
POST /api/v1/administration/teams/createadministration:writeCreate a team
POST /api/v1/administration/teams/updateadministration:writeRename a team or change its members
POST /api/v1/administration/teams/deleteadministration:writeDelete a team that nothing uses
POST /api/v1/administration/api-tokensadministration:readList API keys, and the abilities this token may grant
POST /api/v1/administration/api-tokens/createadministration:writeCreate an API key (only abilities this token holds)
POST /api/v1/administration/api-tokens/updateadministration:writeChange a key’s abilities, IP allow-list or name
POST /api/v1/administration/api-tokens/revokeadministration:writeRevoke an API key
POST /api/v1/administration/licenceadministration:readLicence status + disk utilisation
POST /api/v1/administration/storage/retentionadministration:writeUpdate sent-mail retention
POST /api/v1/administration/storage/delete-orphanedadministration:writeDelete orphaned attachment files
POST /api/v1/administration/storage/delete-closedadministration:writeDelete attachments on old closed tickets
POST /api/v1/administration/diagnosticsadministration:readList/fetch diagnostics (if enabled)
POST /api/v1/administration/diagnostics/fetchadministration:readFetch a file from a diagnostic bundle
POST /api/v1/administration/diagnostics/uploadadministration:writeUpload a diagnostic bundle (multipart)
POST /api/v1/administration/diagnostics/updateadministration:writeUpdate diagnostic metadata

Users

The user endpoints work like Administration → User admin (see User management).

  1. users — optional body q (matches name or email), staff_only (default true: staff and CRM users only; false includes customers) and user_id. Returns users, each with id, name, email, is_staff, is_admin, is_sysadmin, is_superuser, is_api_user, can_crm, tonic_notifications and email_verified_at; queues (id, name, is_inbox_capable); and selected_user: the user named by user_id, or null. selected_user has the same fields plus its queues with their permissions, and two booleans: two_factor_required (Must use two-factor) and two_factor_enrolled (the user has set up two-factor sign-in). The users rows do not carry the two-factor fields; to read them, pass the user’s user_id. The authenticator secret is never returned.
  2. users/create — body name, email, is_staff, is_admin and tonic_notifications, optional can_crm, and is_sysadmin when the token’s owner is a sysadmin. It does not take two_factor_required: set that with users/{user}/update once the user exists. The new user is sent a welcome email. Returns ok and user_id.
  3. users/{user}/update — body is_staff, is_admin and tonic_notifications (always required: send the current values of those you are not changing), plus any of is_api_user, can_crm, two_factor_required and, when the token’s owner is a sysadmin, is_sysadmin. two_factor_required (boolean) is Must use two-factor: it takes effect while System settings → Who must use two-factor sign-in is Selected users or All staff. Setting it to false does not remove a two-factor sign-in the user has already set up. Returns ok and user_id.

Fields not listed are ignored, including is_sysadmin when the token’s owner is not a sysadmin. Making a user staff when every licensed agent seat is in use returns 422.

Teams

The team endpoints work like Administration → Teams. A team is a named group of staff that a ticket can be assigned to. A ticket assigned to a team holds the team’s key, team:<id>, in assigned_to_email, and every member counts as its assignee. Assign tickets to a team by sending its key as assigned_to_email to the Create ticket API or the Reply to ticket API; the keys can also be listed with POST /api/v1/tickets/teams, which needs only the tickets ability. Only staff are members: a user who stops being staff stays on the team’s member list, with is_staff false, but no longer receives its tickets.

The team endpoints use the response envelope described in the API overview: a success is {"ok": true, "data": {…}}. Every id they return — team, member and staff — is a string, as in tickets/teams; ids in a request may be strings or numbers.

  1. teams — no body. Returns teams, in name order, each with id, name, key (team:<id>), members (id, name, email, is_staff), ticket_count (the tickets assigned to the team, closed ones included, deleted ones not), unclosed_count, and three booleans that say what else names the team: has_perspectives (a perspective filters on it), has_quick_actions (a quick action assigns to it or matches on it) and has_interventions (an intervention assigns to it). It also returns staff (id, name, email): the users who can be members.
{
  "ok": true,
  "data": {
    "teams": [
      {
        "id": "4",
        "name": "Billing",
        "key": "team:4",
        "members": [
          { "id": "12", "name": "Jordan Lee", "email": "[email protected]", "is_staff": true },
          { "id": "15", "name": "Sam Dixon", "email": "[email protected]", "is_staff": true }
        ],
        "ticket_count": 18,
        "unclosed_count": 3,
        "has_perspectives": true,
        "has_quick_actions": false,
        "has_interventions": false
      }
    ],
    "staff": [
      { "id": "12", "name": "Jordan Lee", "email": "[email protected]" },
      { "id": "15", "name": "Sam Dixon", "email": "[email protected]" },
      { "id": "21", "name": "Priya Sharma", "email": "[email protected]" }
    ]
  }
}
  1. teams/create — body name (up to 255 characters, unique, and not Unassigned in any capitalisation) and user_ids: the members, as ids from staff. user_ids is required; send [] for a team with no members. Returns team: the new team, in the same shape as an entry of teams, key included.
  2. teams/update — body team_id, name and user_ids, all required: send the current name to keep it. user_ids replaces the membership, so send every member the team should have. The member ids from teams can be sent back as they were read: a member whose is_staff is false is accepted and removed from the team, because only staff are members. A user who is not staff and not already a member is refused. A staff member who joins becomes a participant on the team’s unclosed tickets, so they hear about updates; a member who leaves is not removed as a participant. Returns team as it is after the change.
  3. teams/delete — body team_id. A team that is in use is kept: while any ticket is assigned to it (closed tickets included), or a perspective, quick action or intervention names it, the call returns 422 with "error": "refused" and a message saying which, for example Cannot delete: 3 ticket(s) are assigned to Billing. Reassign those tickets and change those settings first; the counts and flags from teams show what remains. Deleted tickets do not keep a team: any that are still assigned to it are set to Unassigned when the team is deleted, so a ticket restored later is unassigned. Deleting the team also removes its memberships, and a draft that would have assigned its ticket to the team leaves the assignee unchanged instead. Returns deleted (the team’s id) and unassigned_deleted_tickets (how many deleted tickets were set to Unassigned).
{
  "ok": false,
  "error": "refused",
  "message": "Cannot delete: 3 ticket(s) are assigned to Billing."
}

An unknown team_id, a missing or duplicate name, or a user_ids entry that is neither a staff member nor already a member returns 422 with "error": "validation_failed" and errors naming each field. It is JSON whether or not the request sends Accept: application/json. For a non-staff id the message is Only staff can be team members.

{
  "ok": false,
  "error": "validation_failed",
  "errors": {
    "user_ids.1": ["Only staff can be team members."]
  }
}

API keys

The API-key endpoints manage the keys listed on Administration → API keys (see Authentication and tokens). One rule applies on top of the screen’s: a token can only grant abilities it holds itself. A key created or changed through the API can receive only the calling token’s own abilities (holding write covers read), so the API narrows and rotates keys; a key with wider access is created on the screen.

  1. api-tokens — returns tokens, each with id, name, owner (System or the owner’s email), abilities, allowed_ip, last_used_at, expires_at, created_at and is_this_token (true for the key making the call), plus grantable: the abilities this token may grant.
  2. api-tokens/create — body name (up to 255 characters), owner (system or a staff user’s id), abilities (one or more) and optional allowed_ip (a single address the key will only work from). The owner must hold the role each ability requires. The response carries the bearer token once, alongside the stored key:
{
  "ok": true,
  "plain_text_token": "27|Xq4rT9…",
  "token": {
    "id": 27,
    "name": "Sales Portal — tickets read/write",
    "abilities": ["tickets:write"],
    "last_used_at": null,
    "created_at": "2026-10-04T10:15:02.000000Z",
    "allowed_ip": null
  }
}
  1. api-tokens/update — body id plus any of abilities (replaces the list; the owner must hold the role each needs), allowed_ip (an address, or null to remove the restriction) and name. Returns id, name, abilities and allowed_ip.
  2. api-tokens/revoke — body id. The key stops working at once. Returns revoked (the id) and was_this_token, true when a token revoked itself.

Granting an ability the calling token does not hold returns 403 forbidden with a message naming the missing abilities. An unknown key returns 404 not_found; an owner who lacks a required role returns 422 validation_failed.

Not exposed

Some actions are intentionally unavailable over the API, even role-gated, because the blast radius of a leaked token is too high:

  1. Licence register / unregister — can deactivate the whole instance. Read-only status is available above.
  2. Deleting a user — create and role changes are available; deletion is UI-only.
  3. Resetting a user’s two-factor sign-in — a token that could remove a user’s second factor would undo its protection. A system administrator resets it in User admin.