---
title: "Get a line, GET /lines/{id}"
description: "Fetch a single subscriber line by numeric id. Returns the same line object shape used by every other lines endpoint. Reseller keys receive 404 for lines owned by another reseller."
---

# 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](/docs/?page=panel-api-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`](/docs/?page=xai-ref-lines-list) responses, [`GET /lines`](/docs/?page=xai-ref-lines-list) 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`](/docs/?page=xai-ref-lines-list) and [`POST /lines/{id}/disable`](/docs/?page=xai-ref-lines-list) move this field. |
| `admin_enabled` | bool | Admin override. If `false`, the line is blocked no matter what `enabled` says. Only [`POST /lines/{id}/update`](/docs/?page=xai-ref-lines-list) 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. |

```json
{
  "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
}
```

> [!NOTE]
> `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.

## Examples

### cURL

```bash
curl -X GET "https://<your-panel-domain>/panel-api/v1/lines/1512227" \
  -H "Authorization: Bearer <your-api-key>"
```

### PHP SDK

```php
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

```python
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. |

## See also

- [List lines, GET /lines](/docs/?page=xai-ref-lines-list)
- [Get live connections for a line](/docs/?page=xai-ref-lines-connections)
- [Panel API Lines (full guide)](/docs/?page=xai-ref-lines-list)
