Xtream AI API Reference
The Xtream AI API is the native REST flavor of the Panel API. It is designed for new integrations that speak JSON, authenticate with a Bearer token and want a small, predictable surface. Every endpoint under this reference lives at the same base URL, returns JSON with the same envelope, and follows the same rules for pagination, errors and idempotency.
This flavor exists alongside two compatibility surfaces. The Xtream Codes and XUI.one dialect keeps the historical query string layout so legacy code keeps working after a base URL swap. The OneStream dialect keeps the header conventions used by OneStream integrations. All three flavors are served by the same panel and are backed by the same data, so a key issued for one works for all three. The v1 flavor is the one we recommend for new work because the request and response shapes are the most consistent and the SDKs are built on top of it.
Base URL
All endpoints in this reference live under a single base:
https://<your-panel-domain>/panel-api/v1/*
Replace <your-panel-domain> with the domain your customers already use to reach the panel. Every endpoint page in this reference states the exact path it appends to that base, so you can copy the line straight into your client.
Authentication in one paragraph
Every request except GET /health requires an API key sent as Authorization: Bearer <your-api-key>. Keys are issued from the panel UI, carry an explicit list of scopes and can be restricted to a set of source IPs. The full contract, including how to rotate a key, how scopes map to endpoints and how the per-key rate limit is configured, lives in Authentication.
Response shape
Success responses always carry HTTP status in the 2xx range with an application/json body. Single-resource endpoints return an object. List endpoints return the shape below, which is the same for every list in this reference.
{
"items": [
{ "id": 1, "name": "Package 42" },
{ "id": 2, "name": "Package 43" }
],
"next_cursor": 2
}
Failures return a 4xx or 5xx status with a small envelope on every failing call.
{
"error": "validation_error",
"message": "Field 'username' failed validation.",
"request_id": "req_a1b2c3d4e5",
"details": { "field": "username" }
}
Your code should branch on the error slug and treat message as documentation. The request_id also travels back in the X-Request-Id header. Quote it whenever you contact support. The full slug catalog and per-code retry guidance live in Errors.
Pagination for list endpoints
List endpoints return at most 100 items per page. The default page size is 50. Pass limit on the query string to change it within that range.
Every list response includes next_cursor. It is null when the current page is the last one. When it is not null, pass it back as the cursor query parameter to fetch the next page. Treat the value as opaque: today it happens to be a numeric identifier, but future changes may switch it to a token you cannot interpret, and integrations that parse it will break.
curl -H "Authorization: Bearer <your-api-key>" \
"https://<your-panel-domain>/panel-api/v1/lines?limit=100&cursor=172511964"
The order of items on a list is stable across pages, so you can safely walk next_cursor until it comes back null and know you have seen every row exactly once.
Idempotency for writes
Every write endpoint requires an Idempotency-Key header. The API stores the response the first time you send a given key. If your integration retries the same request after a timeout, the API replays the stored response instead of running the write a second time. The value can be any opaque string up to 255 bytes. Business identifiers like invoice-INV-2026-00814 are recommended because they make retries deterministic across restarts of your integration.
The header applies to every POST in this reference, including endpoints that end in /enable, /disable, /renew or /delete. Sending the same key again with a different body returns 409 idempotency_conflict. Sending it while the first request is still running returns 409 idempotency_in_flight. The full contract, retry recipes and worked examples live in Rate limits and Idempotency.
Endpoints in this reference
Every endpoint below is versioned under /panel-api/v1. Public endpoints do not require a key. All other endpoints require a Bearer token with the scope named on the endpoint page.
Public
| Endpoint | Method and path | What it does |
|---|---|---|
| Health check | GET /health |
Returns 200 with {"status":"ok"} when the API layer is up. |
Identity
| Endpoint | Method and path | What it does |
|---|---|---|
| Get caller identity | GET /me |
Returns the identity attached to the calling key. Type (admin or reseller), scopes, billing state and effective permissions. |
Lines
Customer lines. One row per subscription. Every write endpoint under this group requires an Idempotency-Key header.
| Endpoint | Method and path | What it does |
|---|---|---|
| List lines | GET /lines |
Paginated list. Filters by owner, package and expiry. |
| Create a line | POST /lines |
Creates a subscription against a package. Returns the credentials the customer will use to log in. |
| Get a line | GET /lines/{id} |
Full record for a single line. |
| Update a line | POST /lines/{id}/update |
Applies a partial update. Only the fields you send are touched. |
| Enable a line | POST /lines/{id}/enable |
Marks the line as active and allows logins. |
| Disable a line | POST /lines/{id}/disable |
Marks the line as inactive without deleting it. |
| Renew a line | POST /lines/{id}/renew |
Extends the expiry date by a number of months and charges the caller's billing budget. |
| Reset password | POST /lines/{id}/reset-password |
Generates a fresh password for the line. |
| Delete a line | POST /lines/{id}/delete |
Removes the line and its associations. |
| List current connections | GET /lines/{id}/connections |
Snapshot of the sessions currently open against this line. |
Catalog
Read-only. Everything a storefront or reseller dashboard needs to render packages, bouquets, live streams and VODs.
| Endpoint | Method and path | What it does |
|---|---|---|
| List packages | GET /packages |
Every package the caller can sell. |
| List bouquets | GET /bouquets |
Every bouquet the caller can assign to a line. |
| List live streams | GET /streams |
Paginated list of live channels. |
| Get a live stream | GET /streams/{id} |
Full record for one channel. |
| List VODs | GET /vods |
Paginated list of movies. |
| Get a VOD | GET /vods/{id} |
Full record for one movie. |
Resellers
Admin-only endpoints for managing resellers and their billing. A reseller key can only reach POST /resellers and only to create a sub-reseller under itself.
| Endpoint | Method and path | What it does |
|---|---|---|
| List resellers | GET /resellers |
Paginated list of every reseller on the panel. |
| Create a reseller | POST /resellers |
Creates a reseller (admin) or a sub-reseller under the caller (reseller with subresellers:write). |
| Get a reseller | GET /resellers/{id} |
Full record for one reseller. |
| Update a reseller | POST /resellers/{id}/update |
Applies a partial update to the reseller's profile and permissions. |
| Read billing state | GET /resellers/{id}/billing |
Current billing mode (credits or users), balance and effective caps. |
| Adjust billing | POST /resellers/{id}/billing/adjust |
Applies a delta to the reseller's credit balance or user cap. |
Compat flavors
If your code was written for another panel, use the compatibility flavor that already matches its request shape. Both are served alongside the native v1 endpoints and accept the same API keys.
- Xtream Codes and XUI.one compatibility. Same query string layout your existing code already sends. See Xtream Codes compatibility.
- OneStream compatibility. Same header conventions used by OneStream integrations. See OneStream compatibility.
For a broader map of how the three flavors fit together, and when to pick one over another, read the Panel API Overview.