---
title: "Get live connections for a line, GET /lines/{id}/connections"
description: "List the live streaming sessions currently open on a line. Returns up to 200 sessions in reverse-chronological order with client IP, country, and content name."
---

# Get live connections for a line

`GET /lines/{id}/connections` lists the streaming sessions currently open on a subscriber line. It is what support pages call to answer "who is watching what on this account right now, and from where". It is also the endpoint that dashboards poll to render live-viewer counts.

Each item in the response represents one live client (a device or app currently pulling a stream). The list is capped at 200 items ordered by most-recent first, and each item carries the client's IP, country (as inferred by the panel's GeoIP database), the elapsed time since the session opened, and, when the panel can resolve it, the id and name of the content being streamed. Sessions to live channels are labeled `content_type: "live"`; sessions to VOD movies or series episodes are labeled `content_type: "movie"` with a nested `is_serie` flag distinguishing the two.

Tenant isolation matches the rest of `/lines`: a **reseller key** can only inspect connections for lines it owns, and a request for another reseller's line returns `404 not_found` (the same slug used when the id does not exist at all).

## Endpoint

`GET https://<your-panel-domain>/panel-api/v1/lines/{id}/connections`

## 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. Non-numeric values are treated as `0` and return `404 not_found`. |

## Response

An object with a single field:

| Field | Type | Description |
| ----- | ---- | ----------- |
| `items` | Connection[] | Live sessions currently open on the line. Up to 200 items, ordered by `started_at` descending. Empty array when no session is open. |

Each `Connection` item:

| Field | Type | Description |
| ----- | ---- | ----------- |
| `connection_id` | int | Panel-internal id of the live-client session. Stable while the session is open. Not meant to be persisted across sessions. |
| `content_type` | string | Either `"live"` (channel) or `"movie"` (VOD or series episode). For series episodes, `is_serie` is `true`. |
| `content_id` | int or null | Id of the channel or VOD row, when the panel can resolve it. `null` for sessions on channels or VODs the panel cannot cross-reference (typically deleted content that a client is still holding open). |
| `content_name` | string | Human-readable name of the content, or `""` when the panel cannot resolve it. |
| `started_at` | int | UTC Unix epoch when the session opened. |
| `elapsed_sec` | int | Seconds elapsed between `started_at` and the moment the panel served the request. |
| `client_ip` | string | The IP the client is streaming from, as observed by the panel edge. |
| `client_country` | string | ISO 3166-1 alpha-2 country code inferred from `client_ip`. Empty string if the panel's GeoIP database has no answer. |
| `is_serie` | bool | Present only when `content_type == "movie"`. `true` for a series episode, `false` for a stand-alone VOD. |

Empty result (line exists, nobody watching):

```json
{
  "items": []
}
```

Populated result (an active line with many concurrent sessions):

```json
{
  "items": [
    {
      "connection_id": 100000042,
      "content_type": "live",
      "content_id": 5721,
      "content_name": "Package 7 HD",
      "started_at": 1783791431,
      "elapsed_sec": 2415124,
      "client_ip": "203.0.113.14",
      "client_country": "FR"
    },
    {
      "connection_id": 100000041,
      "content_type": "movie",
      "content_id": 8834,
      "content_name": "Movie 42",
      "started_at": 1783791429,
      "elapsed_sec": 2415126,
      "client_ip": "203.0.113.87",
      "client_country": "NL",
      "is_serie": false
    },
    {
      "connection_id": 100000040,
      "content_type": "movie",
      "content_id": 12907,
      "content_name": "Show 3 S01E04",
      "started_at": 1783791429,
      "elapsed_sec": 2415126,
      "client_ip": "203.0.113.140",
      "client_country": "IR",
      "is_serie": true
    }
  ]
}
```

> [!NOTE]
> The 200-item cap means a very active line can have live sessions the endpoint does not return. This is a hard cap in the query, not a paginated page. If you need to audit every session for a reseller with thousands of concurrent connections, iterate the lines first with [`GET /lines`](/docs/?page=xai-ref-lines-list) and call this endpoint per line.

> [!TIP]
> `elapsed_sec` is computed server-side using the current time on the panel, not the caller's clock. It is safe to display without any clock-skew correction.

## Examples

### cURL

```bash
curl -X GET "https://<your-panel-domain>/panel-api/v1/lines/1512227/connections" \
  -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>');
$sessions = $client->lines->connections(1512227);
echo count($sessions) . " active session(s)\n";
foreach ($sessions as $s) {
    echo sprintf("  %s from %s watching %s\n",
        $s->clientIp, $s->clientCountry, $s->contentName ?: '(unresolved)');
}
```

### Python SDK

```python
from xtream_ai_panel_api import PanelApiClient

client = PanelApiClient(base_url="https://<your-panel-domain>", token="<your-api-key>")
sessions = client.lines.connections(1512227)
print(f"{len(sessions)} active session(s)")
for s in sessions:
    print(f"  {s.client_ip} from {s.client_country} watching {s.content_name or '(unresolved)'}")
```

## 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, so no tenant discovery is possible. | 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 lower the polling frequency (this is a live snapshot; polling more often than once every few seconds rarely helps). |
| 503 | `api_disabled` | An admin has turned the Panel API off for this panel. | Contact the panel admin. |

## See also

- [Get a single line, GET /lines/{id}](/docs/?page=xai-ref-lines-get)
- [List lines, GET /lines](/docs/?page=xai-ref-lines-list)
- [Panel API Lines (full guide)](/docs/?page=xai-ref-lines-list)
