> For the complete documentation index, see [llms.txt](https://mava.gitbook.io/mava-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://mava.gitbook.io/mava-docs/webhooks-and-api/api/fetch-tickets.md).

# Fetch Tickets

### Endpoint

```
GET /api/tickets
```

### Authentication

* Requires API token authentication (`x-auth-token` header)
* Subject to rate limiting (90 requests per 30 seconds)

### Query Parameters

| Parameter         | Type                | Required | Default     | Description                                                                                                     |
| ----------------- | ------------------- | -------- | ----------- | --------------------------------------------------------------------------------------------------------------- |
| `startDate`       | string              | **Yes**  | —           | Start of date range (ISO 8601, e.g. `2026-01-01` or `2026-01-01T00:00:00.000Z`)                                 |
| `endDate`         | string              | **Yes**  | —           | End of date range (exclusive). Must be after startDate. Max range: 1 year                                       |
| `limit`           | integer             | No       | `50`        | Number of tickets per page (1–100)                                                                              |
| `skip`            | integer             | No       | `0`         | Number of tickets to skip (for pagination)                                                                      |
| `status`          | string or string\[] | No       | —           | Filter by status. Values: `Open`, `Resolved`, `Pending`, `Waiting`                                              |
| `assignedTo`      | string or string\[] | No       | —           | Filter by agent IDs. Use `Unassigned` for unassigned tickets                                                    |
| `category`        | string or string\[] | No       | —           | Filter by category ID(s)                                                                                        |
| `tags`            | string or string\[] | No       | —           | Filter by tag ID(s)                                                                                             |
| `csatValues`      | string or string\[] | No       | —           | Filter by CSAT rating. Values: `1`–`5` or `no-rating`                                                           |
| `origin`          | string or string\[] | No       | —           | Filter by ticket origin. Values: `web`, `discord`, `telegram`, `telegram-group`, `email`                        |
| `sortBy`          | string              | No       | `createdAt` | Sort field. Values: `createdAt`, `status`, `priority`, `sourceType`, `assignedTo`, `category`, `resolutionTime` |
| `sortOrder`       | string              | No       | `desc`      | Sort direction: `asc` or `desc`                                                                                 |
| `includeMessages` | boolean             | No       | `false`     | When `true`, includes the full message thread for each ticket                                                   |

### Response

**Success (200 OK)**

```json
{
  "tickets": [
    {
      "_id": "6650a1b2c3d4e5f678901234",
      "createdAt": "2026-03-15T10:30:00.000Z",
      "updatedAt": "2026-03-16T14:22:00.000Z",
      "status": "Resolved",
      "priority": 2,
      "sourceType": "discord",
      "resolutionTime": 100920000,
      "assignedTo": {
        "_id": "6650b2c3d4e5f67890123456",
        "name": "Jane Smith"
      },
      "category": {
        "_id": "6650c3d4e5f678901234567a",
        "name": "Billing"
      },
      "tags": [
        { "_id": "6650d4e5f678901234567890", "name": "VIP" }
      ],
      "csat": { "value": 5 },
      "aiStatus": "resolved",
      "discordUsers": [
        { "discordAuthorId": "123456789", "name": "user#1234" }
      ],
      "attributes": [
        { "attributeId": "6650e5f6789012345678abcd", "name": "Plan", "content": "Enterprise" }
      ],
      "customer": {
        "_id": "6650f6789012345678abcdef",
        "email": "user@example.com",
        "attributes": [
          { "attributeId": "665012345678abcdef012345", "name": "Company", "content": "Acme Inc" }
        ]
      },
      "messages": [
        {
          "_id": "665112345678abcdef012345",
          "content": "I need help with my billing",
          "senderType": "customer",
          "senderName": "user#1234",
          "messageType": "ExternalMessage",
          "createdAt": "2026-03-15T10:30:00.000Z",
          "attachments": []
        },
        {
          "_id": "665212345678abcdef012345",
          "content": "Let me look into that for you",
          "senderType": "agent",
          "senderName": null,
          "messageType": "ExternalMessage",
          "createdAt": "2026-03-15T11:00:00.000Z",
          "attachments": []
        }
      ]
    }
  ],
  "count": 285,
  "pagination": {
    "limit": 50,
    "skip": 0,
    "hasMore": true
  }
}
```

#### Response Fields

| Field                   | Description                                                                      |
| ----------------------- | -------------------------------------------------------------------------------- |
| `resolutionTime`        | Milliseconds between creation and resolution. `null` if not resolved             |
| `csat`                  | Customer satisfaction rating (1-5). `null` if no rating or telegram-group ticket |
| `aiStatus`              | AI handling status. `null` for telegram-group tickets                            |
| `discordUsers`          | Discord usernames associated with the ticket. Empty for non-Discord tickets      |
| `customer`              | Customer details with custom attributes. `null` for telegram-group tickets       |
| `messages`              | Only included when `includeMessages=true`. Sorted oldest-first                   |
| `messages[].senderType` | `customer`, `agent`, or `system`                                                 |
| `messages[].senderName` | Discord username when available, otherwise `null`                                |
| `pagination.hasMore`    | `true` if more tickets exist beyond the current page                             |

#### Error Responses

**Missing or invalid date range (400)**

```json
{ "error": "MISSING_DATE_RANGE" }
```

```json
{ "error": "INVALID_DATE_RANGE" }
```

Returned when:

* `startDate` or `endDate` is missing
* Dates are not valid ISO 8601 format
* `endDate` is before or equal to `startDate`
* Date range exceeds 1 year

\
**Invalid limit (400)**

```json
{ "error": "INVALID_LIMIT" }
```

Returned when `limit` is not an integer between 1 and 100.

\
**Invalid skip (400)**

```json
{ "error": "INVALID_SKIP" }
```

Returned when `skip` is negative.

\
**Unsupported sort field (400)**

```json
{ "error": "UNSUPPORTED_SORT_FIELD" }
```

Returned when `sortBy` is not one of the supported values.

\
**Unsupported sort order (400)**

```json
{ "error": "UNSUPPORTED_SORT_ORDER" }
```

Returned when `sortOrder` is not `asc` or `desc`.

\
**Unauthorized (401)**

Returned when the API key is missing or invalid.

**Too Many Requests (429)**

Returned when the rate limit is exceeded. The API allows up to 90 requests per 30 seconds per API key.

**Internal Server Error (500)**

```json
{ "error": "Internal server error" }
```

### Code Examples

**Curl - Basic usage**

```bash
curl -X GET "https://gateway.mava.app/api/tickets?startDate=2026-01-01&endDate=2026-04-01&limit=20" \
  -H "x-auth-token: YOUR_API_KEY"
```

\
**Curl - With filters and messages**

```bash
curl -X GET "https://gateway.mava.app/api/tickets?startDate=2026-01-01&endDate=2026-04-01&status=Open&status=Pending&assignedTo=Unassigned&origin=discord&sortBy=priority&sortOrder=desc&includeMessages=true&limit=10" \
  -H "x-auth-token: YOUR_API_KEY"
```

\
**NodeJS - Basic usage**

```javascript
const params = new URLSearchParams({
  startDate: '2026-01-01',
  endDate: '2026-04-01',
  limit: '20',
  includeMessages: 'true',
});

const response = await fetch(`https://gateway.mava.app/api/tickets?${params}`, {
  method: 'GET',
  headers: {
    'x-auth-token': 'YOUR_API_KEY',
  },
});

const data = await response.json();
console.log(`Found ${data.count} tickets`);
```

\
**NodeJS - Paginate through all results**

```javascript
const limit = 50;
let skip = 0;
let allTickets = [];

while (true) {
  const params = new URLSearchParams({
    startDate: '2026-01-01',
    endDate: '2026-04-01',
    limit: String(limit),
    skip: String(skip),
  });

  const res = await fetch(`https://gateway.mava.app/api/tickets?${params}`, {
    headers: { 'x-auth-token': 'YOUR_API_KEY' },
  });
  const page = await res.json();
  allTickets.push(...page.tickets);

  if (!page.pagination.hasMore) break;
  skip += limit;
}

console.log(`Total tickets fetched: ${allTickets.length}`);
```

#### Filtering by multiple values

To filter by multiple values for the same parameter, repeat the parameter:

```
?status=Open&status=Pending
?origin=discord&origin=email
?csatValues=4&csatValues=5&csatValues=no-rating
```

#### Pagination

Use `skip` and `limit` to paginate through results. The response includes `pagination.hasMore` to indicate whether more pages exist.

1. Start with `skip=0`
2. After each response, if `hasMore` is `true`, increase `skip` by `limit`
3. Repeat until `hasMore` is `false`

The `count` field always reflects the total number of matching tickets across all pages.
