> Source: https://builder.ema.ai/v2/api-reference/ticketing-api
> Title: Ticketing API

# Ticketing API

The Ticketing API is the REST surface behind [Ticketing](/builder/v2/ticketing): one API over every queue, whether the queue runs on the Ema Ticketing Desk or passes through to a connected ServiceNow instance. Use it to raise tickets from your own systems, sync a queue into a report, or drive the same operations the app performs.

All requests require a [JWT or API key](/builder/v2/api-reference/authentication), sent as `Authorization: Bearer <token>` or the `X-API-Key` header. Examples use `https://your-tenant.ema.ai` as the host, and every path below is relative to the service prefix:

```text
https://your-tenant.ema.ai/api/v1/hcm-ticketing
```

> [INFO]
> **Enabled per Workspace.** Every route answers **404** when ticketing is not enabled for the Workspace, for every role, so a not-found on a path you expect to exist means the feature is off rather than the URL being wrong.

## Tickets are addressed by group

Every ticket route carries the group's UUID, and the ticket id is the backend's own handle (a ServiceNow `sys_id`, for example). There is no `/tickets/{id}` route: a queue decides which system a ticket lives in, and no copy is kept in Ema, so the group is what tells the service where to look. Start from `GET /queues` to resolve the group ids you can use.

Authorization follows the app: effective membership of the queue's group is required for every operation (nesting included), System Admins reach every queue, and user groups have to be enabled for the Workspace. A group that auth cannot resolve returns **403** rather than falling back to a Workspace-wide list.

## Queues

Endpoint

What it does

`GET /queues`

The queues the caller may see. Add `?routable=true` to drop queues whose group has been deleted.

`POST /groups/{groupID}/queue`

Bind a group to a queue. Group admin or System Admin.

`PATCH /groups/{groupID}/queue/routing`

Replace the queue's routing guidance, leaving its system and connection alone.

```http
GET https://your-tenant.ema.ai/api/v1/hcm-ticketing/queues
X-API-Key: ema_sk_live_2f9c...redacted
```

```json
{
  "queues": [
    {
      "group_id": "8f14e45f-ea0e-4c7f-9a1a-6f2f0a3b1c22",
      "group_tag": "emahcm-human-resources",
      "name": "Human Resources",
      "backend": "builtin",
      "connection_id": null,
      "routing_description": "Payroll, benefits, and leave questions. High priority for a missed payment.",
      "group_archived": false,
      "request_types": []
    }
  ]
}
```

`backend` is `builtin` for the Ema Ticketing Desk or `servicenow` for a pass-through queue. `request_types` lists the values the queue accepts as a ticket's `type`, in the backend's own order; an absent or empty list means the queue does not publish a closed set, so do not validate against it. Binding a queue takes a `name` (the group's name) and, for `servicenow`, the `connection_id` of a ticketing connection; `builtin` must omit it. The queue's label is derived from the name server-side and is immutable.

## Tickets

Endpoint

What it does

`POST /groups/{groupID}/tickets`

Raise a ticket.

`GET /groups/{groupID}/tickets`

Page the queue, with filters and sort.

`GET /groups/{groupID}/tickets/{ticketID}`

Read one ticket.

`PATCH /groups/{groupID}/tickets/{ticketID}`

Update title, description, priority, type, or labels.

`POST /groups/{groupID}/tickets/{ticketID}/status`

Set `OPEN`, `IN_PROGRESS`, or `HOLD`.

`POST /groups/{groupID}/tickets/{ticketID}/close`

Close it, with an optional `resolution`.

`POST /groups/{groupID}/tickets/{ticketID}/assign`

Assign, or clear the assignee with `null`.

`POST /groups/{groupID}/tickets/{ticketID}/move`

Move to another queue on the same connection. Clears the assignee.

`DELETE /groups/{groupID}/tickets/{ticketID}`

Delete. Group admins and System Admins.

`POST /groups/{groupID}/tickets/{ticketID}/subtickets`

Raise a sub-ticket under this one.

`GET /groups/{groupID}/tickets/{ticketID}/children`

List its sub-tickets.

`GET /me/tickets`

The caller's own tickets across every group they belong to.

```http
POST https://your-tenant.ema.ai/api/v1/hcm-ticketing/groups/8f14e45f-ea0e-4c7f-9a1a-6f2f0a3b1c22/tickets
X-API-Key: ema_sk_live_2f9c...redacted
Content-Type: application/json
```

```json
{
  "client_request_id": "payroll-2026-08-24-4471",
  "title": "August paycheck missing overtime",
  "description": "Overtime hours from the week of Aug 11 are not on the August payslip.",
  "priority": "HIGH",
  "type": "Payroll",
  "tags": ["overtime"]
}
```

`client_request_id` is the idempotency key: a retry carrying the same value does not create a second ticket. `requester_email` defaults to the caller, and naming someone else requires a System Admin or a service principal. `assignee_email` may pre-assign anyone, and any effective member of the group may set it, but the address has to resolve to a real person: a member of the Workspace on the Ema desk, or a user of the instance on a connected queue.

Ticket status is `OPEN`, `IN_PROGRESS`, `HOLD`, or `CLOSED`, and `CLOSED` is reachable only through the close endpoint: sending it to the status endpoint is a **422**. Priority is `CRITICAL`, `HIGH`, `MEDIUM`, or `LOW`, matched case-insensitively on input.

> [WARNING]
> **The `emahcm-` label namespace is reserved.** It carries queue membership, so a `tags` value inside it is rejected (the queue's own tag is the one exception, accepted and dropped). Read a ticket's queue from `group_tag`, and change it with the move endpoint.

## Paging, filtering, and sorting a queue

```http
GET https://your-tenant.ema.ai/api/v1/hcm-ticketing/groups/{groupID}/tickets?status=OPEN&sort=priority&order=asc&page_size=50
```

Parameter

Notes

`status`, `assignee_email`, `requester_email`, `label`

Exact-match filters.

`q`

Case-insensitive substring over title and description. Not ranked.

`created_after`, `created_before`

UTC RFC3339. `after` is inclusive, `before` exclusive.

`sort`

`number`, `priority`, `status`, or `updated_at`. Omitted means newest first.

`order`

`asc` or `desc` over Ema's canonical rank, so `sort=priority&order=asc` is Critical to Low whatever the backend stores. Ignored without `sort`.

`cursor`

Opaque. Pass back verbatim; a cursor from another list, group, or sort is rejected.

`page_size`

Hint. The default is 25 and values above 100 are clamped.

Sorting happens server-side over the whole result set before the page is sliced. Not every backend can honor every key: the response's `sortable_by` advertises the ones this queue can serve, and asking for another is a **422** naming `sort`, rather than an answer in a different order.

`GET /me/tickets` takes `scope` (`created`, `assigned`, or `commented`, defaulting to `created`), the same status, priority, text, and date filters, and an optional `group` to narrow to one group. It carries no `sortable_by`, since it is not a single queue.

## Comments and activity

Endpoint

What it does

`POST /groups/{groupID}/tickets/{ticketID}/comments`

Add a comment. `visibility` is `public` (default, the requester sees it) or `internal`.

`GET /groups/{groupID}/tickets/{ticketID}/comments`

List comments and notes, oldest first.

`GET /groups/{groupID}/tickets/{ticketID}/events`

The activity timeline: `create`, `comment`, `work_note`, and `field_change` entries, oldest first.

A `field_change` entry names the `field` with its `old_value` and `new_value`, canonicalized (status and priority as Ema's values, assignee as an email or name). `actor_type` attributes it: `user` for a person, `ema` for an AI Employee, `service` for an account the system of record itself treats as a machine user. For a connected queue this history is read live from that system rather than from a copy in Ema.

## Errors

Status

Meaning

401

Missing or invalid credentials.

403

Not an effective member of the queue's group, user groups not enabled, a requester named by a caller without the privilege to name one, or the queue's connection refusing the request (`CONNECTION_FORBIDDEN`).

404

Ticketing not enabled for the Workspace, no queue configured for the group, or an unknown group or ticket.

409

State-dependent rejection: a write against a closed ticket, or a double close.

413

Body over 1 MiB.

422

A value outside the accepted domain: `CLOSED` on the status endpoint, a sort key this queue cannot serve, a reserved label, an unresolvable assignee, a request type the queue does not accept, or a replayed cursor.

424

The queue's connection has been deleted, disconnected, or is misconfigured. Fix or repoint the connection; retrying will not help.

503

The backend is transiently unavailable, or its connection could not be resolved. Retry.

## What's next

-   [Ticketing](/builder/v2/ticketing) for what queues are and how they are set up.
-   [Ticket Tools](/builder/v2/ticketing/ticket-tools) for the tools that wrap this API for AI Employees.
-   [Authentication](/builder/v2/api-reference/authentication) for tokens and API keys.
