---
title: "action=get_movies"
description: "List VOD entries (movies and series episodes) in the panel catalog. Paginated with limit and start (offset). Response includes a next_cursor."
---

# action=get_movies

Lists VOD entries in the panel catalog. Despite the name, this endpoint returns both standalone movies and individual series episodes; the `is_serie` flag on each item tells them apart. Both admin and reseller keys see the full catalog; this endpoint is not filtered by reseller (same reasoning as [action=get_streams](/docs/?page=xc-ref-streams-list)).

Accepts classic XC `limit` and `start` pagination, with a `next_cursor` in the response for callers that want to follow the keyset chain.

## Endpoint

`GET https://<your-panel-domain>/panel-api/xc/{accesscode}/admin/index.php?action=get_movies`

Also accepted: POST with `action=get_movies` in the body, and the `/reseller/index.php` sub-path.

## Authentication

Send the API key as `?api_key=<token>`, as an `api_key=<token>` POST field, or as `Authorization: Bearer <token>`.

## Required scope

`vods:read`. A key without the scope gets `STATUS_NO_PERMISSIONS` with `error: "insufficient_scope"`.

## Query parameters

| Name | Type | Required | Default | Description |
| ---- | ---- | -------- | ------- | ----------- |
| `action` | string | Yes | | Must be `get_movies`. |
| `api_key` | string | Yes (if not using Bearer) | | The API key. |
| `limit` | int | No | `50` | Page size. Minimum `1`, maximum `100`. Values above `100` are silently clamped. |
| `start` | int | No | `0` | Best-effort offset. Mapped to the native `cursor` (return items with `id > start`). See [Pagination](#pagination) below. |

## Response

`data.items` is the current page of VOD objects. `data.next_cursor` is the id of the last item in the page, or `null` on the last page.

```json
{
  "status": "STATUS_SUCCESS",
  "data": {
    "items": [
      {
        "id": 83287,
        "name": "Movie 83287",
        "icon": "",
        "year": 2019,
        "rating": 7.1,
        "is_serie": true,
        "categories": []
      },
      {
        "id": 83288,
        "name": "Movie 83288",
        "icon": "",
        "year": 2019,
        "rating": 7.1,
        "is_serie": true,
        "categories": []
      },
      {
        "id": 83289,
        "name": "Movie 83289",
        "icon": "",
        "year": 2019,
        "rating": 8.6,
        "is_serie": true,
        "categories": []
      }
    ],
    "next_cursor": 83289
  }
}
```

Field-by-field.

| Field | Type | Description |
|---|---|---|
| `id` | int | VOD id. Use it with [action=get_movie](/docs/?page=xc-ref-movies-get) for detail. |
| `name` | string | Title. For series episodes typically formatted as `Show - SxxEyy - Episode title`. |
| `icon` | string | Absolute URL of the poster or cover image, or empty string if none. |
| `year` | int | Release year, `0` if unknown. |
| `rating` | float | Rating (0-10 scale), `0` if not rated in the panel database. |
| `is_serie` | bool | `true` if the entry is a series episode, `false` if a standalone movie. |
| `categories` | array | Zero or more category objects (`id`, `name`). May be empty. |

## Pagination

Same semantics as [action=get_streams](/docs/?page=xc-ref-streams-list#pagination). The compat layer maps `start = N > 0` to native `cursor = N`, meaning the response contains items with `id > N`. Feed `next_cursor` back in as `start=<next_cursor>` on the next request. Stop when `next_cursor` is `null`.

For sparse id spaces (VOD catalogs where entries have been deleted historically), the `start` mapping is best-effort. For reliable pagination over a large catalog, use the native `GET /panel-api/v1/vods` and consume `next_cursor` directly (see [Panel API Catalog](/docs/?page=xai-ref-overview#vods)).

## Examples

### cURL

```bash
# First page
curl "https://<your-panel-domain>/panel-api/xc/panel_api/admin/index.php?api_key=<your-api-key>&action=get_movies&limit=50"

# Next page by cursor
curl "https://<your-panel-domain>/panel-api/xc/panel_api/admin/index.php?api_key=<your-api-key>&action=get_movies&limit=50&start=83289"
```

### PHP raw

```php
$base  = 'https://<your-panel-domain>/panel-api/xc/panel_api/admin/index.php';
$token = '<your-api-key>';

$start   = 0;
$movies  = 0;
$episodes = 0;
do {
    $url = $base . '?' . http_build_query([
        'api_key' => $token,
        'action'  => 'get_movies',
        'limit'   => 100,
        'start'   => $start,
    ]);
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $body = json_decode(curl_exec($ch), true);
    curl_close($ch);
    if (($body['status'] ?? '') !== 'STATUS_SUCCESS') {
        throw new RuntimeException('get_movies failed: ' . ($body['data']['message'] ?? 'unknown'));
    }
    foreach ($body['data']['items'] as $v) {
        if ($v['is_serie']) $episodes++; else $movies++;
    }
    $start = $body['data']['next_cursor'];
} while ($start !== null);

printf("Catalog: %d movies, %d series episodes\n", $movies, $episodes);
```

### Python raw

```python
import requests

base  = "https://<your-panel-domain>/panel-api/xc/panel_api/admin/index.php"
token = "<your-api-key>"

start = 0
movies, episodes = 0, 0
while True:
    r = requests.get(base, params={
        "api_key": token,
        "action":  "get_movies",
        "limit":   100,
        "start":   start,
    }, timeout=30)
    r.raise_for_status()
    body = r.json()
    if body["status"] != "STATUS_SUCCESS":
        raise RuntimeError(f"get_movies failed: {body['data'].get('message')}")
    for v in body["data"]["items"]:
        if v["is_serie"]:
            episodes += 1
        else:
            movies += 1
    start = body["data"]["next_cursor"]
    if start is None:
        break

print(f"Catalog: {movies} movies, {episodes} series episodes")
```

## Errors

| `status` | `error` slug | When it happens | How to fix |
| -------- | ----------- | --------------- | ---------- |
| `STATUS_INVALID_DATA` | `validation_error` | `action` parameter is missing. | Include `action=get_movies`. |
| `STATUS_NO_PERMISSIONS` | `insufficient_scope` | Key does not carry `vods:read`. | Issue a new key with the scope. |
| `STATUS_FAILURE` | `invalid_key` | Key not sent or not recognized. | Check the key value. |
| `STATUS_FAILURE` | `rate_limited` | Per-minute request budget exceeded. | Slow down. See [Rate limits & Idempotency](/docs/?page=panel-api-rate-limits-idempotency). |

## See also

- [action=get_movie](/docs/?page=xc-ref-movies-get). Detail for a single VOD entry.
- [action=get_streams](/docs/?page=xc-ref-streams-list). Companion listing for live channels.
- [Panel API Catalog](/docs/?page=xai-ref-overview#vods). Native v1 endpoint with richer filters.
