Get a line
GET /lines/{id} reads a single subscriber line by its panel-wide numeric id and returns the canonical line object. It is the endpoint every dashboard, ticket viewer, and billing sync calls when it already knows which line it wants to look at.
The endpoint enforces the same tenant isolation as the list endpoint. An admin key can fetch any line on the panel. A reseller key can only fetch lines it owns (member_id == reg_user_id); every other id returns 404 not_found, even if that id exists on the panel. This is intentional: it means the API never leaks the existence of lines that belong to another tenant.
Endpoint
GET https://<your-panel-domain>/panel-api/v1/lines/{id}
Authentication
Bearer token in the Authorization header. See Authentication.
Required scope
lines:read.
Path parameters
| Name | Type | Description |
|---|---|---|
id |
int | The line's panel-wide numeric id. Stable for the life of the line. Non-numeric values are treated as 0 and return 404 not_found. |
Response
Returns the line object. Same shape used by POST /lines responses, GET /lines items, and every enable / disable / renew / update response.
| Field | Type | Description |
|---|---|---|
id |
int | Panel-wide numeric id. Stable for the life of the line. |
username |
string | The stream username. Autogenerated as u_<8hex> (or trial_<8hex> for trials) when the line was created without an explicit value. |
password |
string | The stream password. Returned in clear, unhashed. |
member_id |
int | Owner's reg_user_id. Reseller keys always see their own id here. |
exp_date |
int or null | Expiry as a UTC Unix epoch. null means the line never expires (perpetual). |
max_connections |
int | Concurrent-connection cap, in the range [1, 100]. |
is_trial |
bool | true if the line was created from a trial package. |
is_restreamer |
bool | true if the line is allowed to restream through the panel. |
enabled |
bool | Reseller-visible toggle. The two endpoints POST /lines/{id}/enable and POST /lines/{id}/disable move this field. |
admin_enabled |
bool | Admin override. If false, the line is blocked no matter what enabled says. Only POST /lines/{id}/update can change it. |
bouquets |
int[] | Bouquet ids assigned to the line. |
created_at |
int or null | Creation timestamp (UTC Unix epoch). Can be null on very old lines migrated in without a timestamp. |
{
"id": 1512227,
"username": "u_ab12cd34",
"password": "9f3c1a77",
"member_id": 42,
"exp_date": 1813449600,
"max_connections": 4,
"is_trial": false,
"is_restreamer": false,
"enabled": true,
"admin_enabled": true,
"bouquets": [2, 4, 14, 15, 82, 107, 108, 110, 112, 114, 115, 118, 120, 134],
"created_at": 1574874852
}
passwordis returned in clear on every response that includes the line object. If your integration must not log passwords, mask this field before writing to your own logs. The panel's own access log format already masks the query string on/panel-api/*routes, but the response body is your responsibility.
Examples
cURL
curl -X GET "https://<your-panel-domain>/panel-api/v1/lines/1512227" \
-H "Authorization: Bearer <your-api-key>"
PHP SDK
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>');
$line = $client->lines->get(1512227);
echo $line->username . " expires at " . ($line->expDate ?? 'never') . "\n";
Python SDK
from xtream_ai_panel_api import PanelApiClient
client = PanelApiClient(base_url="https://<your-panel-domain>", token="<your-api-key>")
line = client.lines.get(1512227)
print(f"{line.username} expires at {line.exp_date or 'never'}")
Errors
| HTTP | Error slug | When it happens | How to fix |
|---|---|---|---|
| 401 | invalid_key |
The Authorization header is missing, malformed, points to an unknown key, or the key is disabled, expired, deleted, or IP-restricted. |
Verify the token. Reissue if it was rotated. |
| 403 | insufficient_scope |
The key does not have lines:read. |
Grant lines:read from the panel or issue a new key with that scope. |
| 404 | not_found |
The id does not exist, or a reseller key is asking for a line owned by a different reseller. Both cases return the same body. | Confirm the id and, if you are using a reseller key, that the line's member_id matches your own reg_user_id. |
| 429 | rate_limited |
You exceeded the key's per-minute rate limit or the panel-wide per-IP limit. | Honor the Retry-After header and cache the response. |
| 503 | api_disabled |
An admin has turned the Panel API off for this panel. | Contact the panel admin. |