---
title: "List bouquets"
description: "Returns every bouquet the calling key can attach to a line. Read-only. Used by signup forms and reseller dashboards to render the playlist picker."
---

# List bouquets

Returns every bouquet the calling key can attach to a line. Bouquets are named groupings of live channels and VODs; when you create a line you pass a list of bouquet ids and those become the subscriber's playlist. If you omit `bouquets` at line creation time, the panel copies the package's default bouquet list.

The endpoint is scoped silently by caller type. An admin key sees every bouquet in the panel. A reseller key sees the union of `bouquets` across the packages they can sell (cached server side for five minutes). No error is raised when the visible set is empty; the response is `{"items": []}`.

## Endpoint

`GET https://<your-panel-domain>/panel-api/v1/bouquets`

## Authentication

Bearer token in the `Authorization` header. See [Authentication](/docs/?page=panel-api-authentication).

## Required scope

`bouquets:read`.

## Query parameters

This endpoint takes no query parameters. Bouquets are ordered by their internal `order` field (the same order shown in the panel UI) and the full list is returned in one call.

## Response

The response wraps the list in an `items` array. Each item has the following fields.

| Field | Type | Description |
| ----- | ---- | ----------- |
| `id` | int | Numeric bouquet id. Stable across the panel's lifetime. |
| `name` | string | Human readable name shown in the panel UI. |
| `order` | int | Sort key used by the panel UI. Lower values render first. Multiple bouquets can share the same `order` value. |

Example response.

```json
{
  "items": [
    {
      "id": 119,
      "name": "Bouquet 5",
      "order": 0
    },
    {
      "id": 136,
      "name": "Bouquet 12",
      "order": 0
    },
    {
      "id": 135,
      "name": "Bouquet 18",
      "order": 0
    }
  ]
}
```

> [!NOTE]
> The bouquet response does not include the list of channels or VODs the bouquet contains. To enumerate what plays inside a bouquet you build the list on your side using [List live streams](/docs/?page=xai-ref-catalog-streams) and [List VODs](/docs/?page=xai-ref-catalog-vods) filtered by `category_id`, or you show the bouquet name only (which is what most storefronts do).

## Examples

### cURL

```bash
curl -H "Authorization: Bearer <your-api-key>" \
     https://<your-panel-domain>/panel-api/v1/bouquets
```

### PHP SDK

```php
require __DIR__ . '/api-panel-php-sdk-1.0.0/autoload.php';
use XtreamAI\PanelApi\PanelApiClient;

$client = new PanelApiClient(baseUrl: 'https://<your-panel-domain>', token: '<your-api-key>');

$bouquets = $client->catalog->bouquets();
foreach ($bouquets as $b) {
    echo $b->id, ' ', $b->name, PHP_EOL;
}
```

### Python SDK

```python
from xtream_ai_panel_api import PanelApiClient

client = PanelApiClient(base_url="https://<your-panel-domain>", token="<your-api-key>")

bouquets = client.catalog.bouquets()
for b in bouquets:
    print(b.id, b.name)
```

## Errors

| HTTP | Error slug | When it happens | How to fix |
| ---- | ---------- | --------------- | ---------- |
| 401 | `invalid_key` | The `Authorization` header is missing, malformed, or names a key that does not exist. | Check the header. See [Authentication](/docs/?page=panel-api-authentication). |
| 403 | `insufficient_scope` | The key does not carry `bouquets:read`. | Regenerate the key with `bouquets:read` in its scope list, or use a key that has it. |
| 429 | `rate_limited` | The per key rate limit has been exceeded. Response carries `Retry-After: 60` and `X-RateLimit-*` headers. | Back off for the number of seconds in `Retry-After` and retry. |

## See also

- [List packages](/docs/?page=xai-ref-catalog-packages)
- [Create a line](/docs/?page=xai-ref-lines-create)
- [Catalog overview](/docs/?page=xai-ref-overview)
