XC and XUI API Reference

The XC compatibility dialect keeps the wire format of the classic Xtream Codes, Xtream-Masters, XUI.one, and OTT Panel API. If your integration was written against any of those panels, you point it at Xtream AI by changing the base URL and swapping in a new API key. Nothing else in your code has to move.

This reference is written for readers who already know the classic contract. Every page in the section documents one action in the same shape: request, response, examples, errors, cross-references. If you are starting a new integration instead of migrating an old one, prefer the native v1 API with the official SDKs. The compatibility dialect is designed to unblock migration, not to be the recommended long-term shape.

A guided introduction to the dialect, including the full field-by-field mapping table and idempotency semantics via rid, lives in the Xtream Codes / XUI.one / OTT Panel Compatibility migration guide. This reference cross-links back to that page for cases where the mapping is not obvious.

Base URL

Every action goes through one of these two paths.

https://<your-panel-domain>/panel-api/xc/{accesscode}/admin/index.php
https://<your-panel-domain>/panel-api/xc/{accesscode}/reseller/index.php

The {accesscode} path segment is decorative. Any non-empty string works. Classic panels used it as a shared secret mixed with the API key. Xtream AI enforces security purely through the API key, so you can leave whatever value your current integration hardcodes (panel_api, xc, xtream, whatever). The routing behavior is identical.

The admin and reseller sub-paths are also interchangeable. The API infers the caller identity from the key itself, not from the URL. If your existing integration hardcodes admin/index.php, keep that. If it hardcodes reseller/index.php, keep that. Both accept the same key types.

Authentication

The dialect accepts three ways to send the API key.

  • ?api_key=<token> in the query string. This is the classic XC form and is accepted for both GET and POST.
  • api_key=<token> as a POST body field. Useful if your integration prefers to keep credentials out of URLs.
  • Authorization: Bearer <token> HTTP header. A modern alternative if you want the key out of logs and referrer headers without rewriting every call.

If you send the key both in the query and in the body, or in both the query and the Authorization header, the values must match. Conflicting values are rejected. See Panel API Authentication for the token shape, scopes, IP allow-lists, and per-key rate limits.

Response envelope

Every response has the classic XC shape, always over HTTP 200.

{
  "status": "STATUS_SUCCESS",
  "data": { "...": "..." }
}

HTTP 200 is used even for authentication failures, missing parameters, forbidden actions, and upstream errors. Widely deployed XC clients branch on the status field, not on the HTTP status code, and we preserve that contract. The only cases where you will see a non-200 HTTP status are real network failures and infrastructure errors from the load balancer.

On failure, data contains a small object you can log.

{
  "status": "STATUS_FAILURE",
  "data": {
    "error": "not_found",
    "message": "Line not found"
  }
}

The status values that this dialect can return are STATUS_SUCCESS, STATUS_INVALID_DATA, STATUS_NO_PERMISSIONS, STATUS_INSUFFICIENT_CREDITS, STATUS_INVALID_PACKAGE, and STATUS_FAILURE. The full mapping from native error slugs to XC status values is in the compatibility guide. The error slugs themselves are catalogued on the Panel API Errors page.

Supported actions

Every action below is implemented today and translated transparently to the underlying native handler.

Info and read-only

Action Description Reference
user_info Identity of the calling key, plus scopes and (for reseller keys) billing shape. action=user_info
packages (alias get_packages) Every package the caller can use to create a line. action=packages
get_bouquets Every bouquet the caller can assign to a line. action=get_bouquets
get_streams List of live streams in the panel catalog. action=get_streams
get_stream A single live stream by id. action=get_stream
get_movies List of VOD entries (movies and episodes). action=get_movies
get_movie A single VOD entry by id. action=get_movie

Lines (read)

Action Description Reference
get_lines Lines belonging to the caller. Supports username filter and DataTables-style search[value]. Xtream Codes / XUI.one compat page
get_line A single line by id. Xtream Codes / XUI.one compat page

Lines (write)

Action Description Reference
create_line Create a new subscriber line. Xtream Codes / XUI.one compat page
edit_line Update password, expiry, connections, restreamer flag, enabled state, IP or UA allow-lists. Xtream Codes / XUI.one compat page
extend_line Renew a line using a package. Xtream Codes / XUI.one compat page
enable_line Re-enable a suspended line. Xtream Codes / XUI.one compat page
disable_line Suspend a line without refund. Xtream Codes / XUI.one compat page
delete_line Permanently delete a line. Xtream Codes / XUI.one compat page

Sub-resellers

Action Description Reference
get_users List of sub-resellers under the caller. Xtream Codes / XUI.one compat page
get_user A single reseller by id. Xtream Codes / XUI.one compat page
create_user Create a sub-reseller (billing mode, credits, quotas). Xtream Codes / XUI.one compat page
edit_user Update fields on an existing sub-reseller. Xtream Codes / XUI.one compat page
adjust_credits Credit or debit a reseller balance with an audit note. Xtream Codes / XUI.one compat page

Unsupported actions

Two families of classic actions are rejected on purpose.

  • mysql_query returns STATUS_FAILURE with error: "forbidden_action". Arbitrary SQL execution over HTTP is a foot-gun and is intentionally not exposed by this API.
  • Every MAG action (get_mag, create_mag, delete_mag, and the rest) and every Enigma action (get_enigma, create_enigma, and the rest) returns STATUS_FAILURE with error: "not_implemented". Xtream AI does not provision physical MAG or Enigma devices; the equivalent product concept is a subscriber Line with the appropriate flags on the client device.

The full list and the exact response bodies are on the unsupported actions page.

Idempotency via rid

Classic XC panels have no idempotency layer. Xtream AI adds one on top of the compatibility dialect: on any write action, pass a rid=<unique-per-operation> parameter (in the query string or the POST body) and the same request repeated with the same rid returns the original response back without running the operation twice. The rid is optional (each write runs independently if you omit it) and lives in a 24-hour window scoped to the API key. See Idempotency via rid for the full contract.

Examples

cURL

curl "https://<your-panel-domain>/panel-api/xc/panel_api/admin/index.php?api_key=<your-api-key>&action=user_info"

PHP raw

$url = 'https://<your-panel-domain>/panel-api/xc/panel_api/admin/index.php'
     . '?' . http_build_query([
         'api_key' => '<your-api-key>',
         'action'  => 'user_info',
       ]);
$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('Panel error: ' . ($body['data']['message'] ?? 'unknown'));
}

Python raw

import requests

r = requests.get(
    "https://<your-panel-domain>/panel-api/xc/panel_api/admin/index.php",
    params={"api_key": "<your-api-key>", "action": "user_info"},
    timeout=30,
)
r.raise_for_status()
body = r.json()
assert body["status"] == "STATUS_SUCCESS"

See also