## List tickets

`GET /v1/feedback`

Returns a list of tickets with filters and pagination. A key without the `vibe:feedback` scope sees only the tickets it sent itself, a key with the scope sees every ticket of its Bitrix24 account, and a management key sees tickets from all Bitrix24 accounts. Newest tickets come first.

## Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|:--------:|---------|-------------|
| `status` (query) | string | no | — | `NEW`, `REVIEWING`, `AWAITING_USER`, `NEEDS_REVIEW`, `RESOLVED`, `ARCHIVED`, `WITHDRAWN`. Case-insensitive |
| `category` (query) | string | no | — | `BUG`, `SUGGESTION`, `DOCS`, `CHAT`, `BOTS`, `OTHER`. Case-insensitive |
| `offset` (query) | number | no | `0` | How many records to skip |
| `page` (query) | number | no | `1` | Page-based pagination. Used when `offset` is not set |
| `limit` (query) | number | no | `20` | Page size, from 1 to 100. A value above 100 is capped at 100; zero and a non-numeric value are replaced with `20` |
| `filter[status]`, `filter[category]` (query) | string | no | — | The same two filters in bracket form |
| `exported` (query) | string | no | — | `true` — only tickets handed to developers, `false` — only those not handed over. Applies to a key with the `vibe:feedback` scope and to a management key; other keys ignore it |
| `portalId` (query) | string | no | — | Bitrix24 account UUID. Narrows a management key's results to one Bitrix24 account; other keys ignore it |

To page through results, use `offset` — for example `offset=100&limit=50`. The `offset` field in the response echoes the applied offset. If `offset` is not passed, `page` is used.

The `status` and `category` filters are case-insensitive (`status=new` is equivalent to `status=NEW`). An unknown value returns `400 INVALID_FILTER_VALUE` — a typo in a filter is rejected explicitly instead of yielding the whole list.

The same two filters are accepted in bracket form: `filter[status]=NEW&filter[category]=BUG`. Validation is identical — case-insensitive, and an unknown value returns `400 INVALID_FILTER_VALUE`. When both forms are present, the flat one is applied. A non-scalar value (`filter[status][]=NEW`) is also rejected with `400 INVALID_FILTER_VALUE`.

## Examples

### curl — personal key

```bash
curl -H "X-Api-Key: YOUR_API_KEY" \
  "https://vibecode.bitrix24.com/v1/feedback?status=NEW&category=BUG&limit=20"
```

### curl — OAuth application

```bash
curl -H "X-Api-Key: YOUR_APP_KEY" \
  -H "Authorization: Bearer USER_SESSION_TOKEN" \
  "https://vibecode.bitrix24.com/v1/feedback?status=NEW&category=BUG&limit=20"
```

### JavaScript — personal key

```javascript
const res = await fetch(
  'https://vibecode.bitrix24.com/v1/feedback?status=NEW&category=BUG&limit=20',
  { headers: { 'X-Api-Key': 'YOUR_API_KEY' } },
)
const { data, total } = await res.json()
```

### JavaScript — OAuth application

```javascript
const res = await fetch(
  'https://vibecode.bitrix24.com/v1/feedback?status=NEW&category=BUG&limit=20',
  { headers: { 'X-Api-Key': 'YOUR_APP_KEY', 'Authorization': 'Bearer USER_SESSION_TOKEN' } },
)
const { data, total } = await res.json()
```

## Response fields

| Field | Type | Description |
|-------|------|-------------|
| `success` | boolean | Always `true` on success |
| `data` | array | Array of tickets |
| `data[].id` | string | Ticket UUID |
| `data[].category` | string | Category |
| `data[].title` | string | Title |
| `data[].body` | string | Description |
| `data[].status` | string | Current status |
| `data[].source` | string | `api` or `ui` |
| `data[].resolution` | string · null | The verdict recorded at the last closure. Empty on a ticket that was never closed. Reopening keeps the verdict, so the field can be non-empty on an active ticket — for the team's latest answer, read the comment thread |
| `data[].attachmentCount` | number | Number of attachments |
| `data[].context` | object · null | The original JSON passed at creation |
| `data[].portalId` | string | UUID of the Bitrix24 account the ticket was sent from |
| `data[].portalDomain` | string | Domain of that Bitrix24 account |
| `data[].userId` | string · null | UUID of the user who sent the ticket. `null` for a ticket without an author, for example when the author was deleted |
| `data[].userName` | string · null | Name of that user. `null` together with `userId` |
| `data[].apiKeyId` | string · null | ID of the key the ticket was sent with |
| `data[].securityFlags` | object · null | Internal moderation marks. `null` when there are none |
| `data[].gitlabIssueIid` | number · null | Issue number in the team's tracker if the ticket was handed to developers. Otherwise `null` |
| `data[].exportedAt` | string · null | When the ticket was handed to developers (ISO 8601). Otherwise `null` |
| `data[].createdAt` | string | Creation date (ISO 8601) |
| `data[].resolvedAt` | string · null | Closing date, if any |
| `total` | number | Total records matching the filter |
| `page` | number | Current page |
| `limit` | number | Page size |
| `offset` | number | Applied offset |

The fields from `context` to `exportedAt` are returned only to a key with the `vibe:feedback` scope and to a management key.

## Response example

```json
{
  "success": true,
  "data": [
    {
      "id": "a1b2c3d4-1111-2222-3333-444455556666",
      "category": "BUG",
      "title": "POST /v1/deals/search returns 500 on empty filter",
      "body": "Calling POST /v1/deals/search with body {\"filter\":{}} gives a 500.",
      "status": "NEW",
      "source": "api",
      "resolution": null,
      "attachmentCount": 0,
      "createdAt": "2026-04-19T10:30:00.000Z",
      "resolvedAt": null
    }
  ],
  "total": 1,
  "page": 1,
  "limit": 20,
  "offset": 0
}
```

## Error response example

400 — unknown filter value:

```json
{
  "success": false,
  "error": {
    "code": "INVALID_FILTER_VALUE",
    "message": "Invalid status 'BOGUS'. Allowed values: NEW, REVIEWING, AWAITING_USER, NEEDS_REVIEW, RESOLVED, ARCHIVED, WITHDRAWN."
  }
}
```

## Errors

| HTTP | Code | Description |
|------|------|-------------|
| 400 | `INVALID_FILTER_VALUE` | An unknown `status` or `category` value was passed |
| 400 | `INVALID_INPUT` | `exported` is neither `true` nor `false`. Checked only for a key with the `vibe:feedback` scope and a management key |
| 401 | `MISSING_API_KEY` | The `X-Api-Key` header was not passed |

For the full list of common API errors, see [Errors](/docs/errors).

## See also

- [Get a ticket](/docs/feedback/get)
- [Submit a ticket](/docs/feedback/submit)
- [Feedback](/docs/feedback)
- [Errors](/docs/errors)
