Get a line

action=get_line reads a single subscriber line by its panel-wide numeric id and returns the canonical Line object wrapped in the classic {"status": "STATUS_SUCCESS", "data": {...}} envelope. The request is translated to the native GET /panel-api/v1/lines/{id} and its response is rewrapped, so scoping and shape are identical to the native endpoint.

Tenant isolation is enforced. 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 STATUS_FAILURE with not_found, even if that id exists on the panel. The API never leaks the existence of another tenant's line.

Endpoint

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

Both /admin/index.php and /reseller/index.php are accepted. The path segment is decorative; the admin-versus-reseller decision comes from the key. See the compatibility overview for the full URL contract.

Authentication

Any one of these three forms:

  • ?api_key=<your-api-key> in the query string.
  • api_key=<your-api-key> in a POST body form field.
  • Authorization: Bearer <your-api-key> HTTP header.

See Authentication.

Required scope

lines:read.

Query parameters

Name Type Required Default Description
action string yes Must be get_line.
api_key string yes (unless sent via Bearer header or body) Your Panel API token.
id int yes The line's panel-wide numeric id. Non-numeric values are treated as 0 and return STATUS_FAILURE with not_found. Missing values return STATUS_INVALID_DATA with validation_error.

Response

data is the Line object. Same shape used by every other lines action in the XC dialect and by the native GET /panel-api/v1/lines/{id}.

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. enable_line and disable_line move this field.
admin_enabled bool Admin override. If false, the line is blocked no matter what enabled says. Only edit_line on an admin key 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.
{
  "status": "STATUS_SUCCESS",
  "data": {
    "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
  }
}

password is 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.

HTTP status is always 200, even for not_found and invalid_key. Branch on status inside the envelope, not on the HTTP code.

Examples

cURL

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

PHP (raw HTTP)

$url = 'https://<your-panel-domain>/panel-api/xc/panel_api/admin/index.php'
     . '?' . http_build_query([
         'api_key' => '<your-api-key>',
         'action'  => 'get_line',
         'id'      => 1512227,
       ]);
$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($body['data']['message'] ?? 'get_line failed');
}
$line = $body['data'];
echo $line['username'], ' exp=', $line['exp_date'], PHP_EOL;

Python (raw HTTP)

import requests

r = requests.get(
    "https://<your-panel-domain>/panel-api/xc/panel_api/admin/index.php",
    params={"api_key": "<your-api-key>", "action": "get_line", "id": 1512227},
    timeout=30,
)
r.raise_for_status()
body = r.json()
if body.get("status") != "STATUS_SUCCESS":
    raise RuntimeError(body.get("data", {}).get("message", "get_line failed"))
line = body["data"]
print(line["username"], "exp=", line["exp_date"])

Errors

Response is always HTTP 200. Branch on status, then on data.error for the slug.

status Error slug When it happens How to fix
STATUS_INVALID_DATA validation_error The id query parameter is missing or empty. data.details.field is "id". Send a numeric id.
STATUS_FAILURE not_found The id does not exist, or a reseller key targeted a line owned by another reseller. Verify the id and ownership.
STATUS_FAILURE invalid_key The token is missing, unknown, disabled, expired, or the source IP is not in the key's allow-list. Verify the token. Check the IP allow-list.
STATUS_NO_PERMISSIONS insufficient_scope The key does not have lines:read. Grant lines:read or issue a new key.
STATUS_FAILURE rate_limited Per-minute cap or per-IP cap exceeded. Back off.
STATUS_FAILURE api_disabled An admin has switched the Panel API off for this panel. Contact the panel admin.

See also