---
title: "Update a line, POST /ext/line/{uuid}/update-advanced"
description: "Change password, expire_at, is_enabled, is_restreamer, or max_connections on an existing line. Fields that this API cannot update are rejected explicitly rather than silently ignored."
---

# Update a line, POST /ext/line/{uuid}/update-advanced

> [!NOTE]
> If you are starting a new integration instead of migrating, prefer the [native v1 API](/docs/?page=xai-ref-lines-update) with the [official SDKs](/docs/?page=panel-api-sdks). The OneStream dialect exists to let existing OneStream code point at Xtream AI with only a base URL change.

Change selected fields on an existing line. Only five fields are editable through this endpoint: `password`, `expire_at`, `is_enabled`, `is_restreamer`, and `max_connections`. Anything else your OneStream client sends (`username`, `bouquets`, `reseller_notes`, `is_trial`, and so on) is rejected up front with `422 validation_error` so you never get a silent `200 OK` on a change that did not actually apply.

The response is the full line object with the updated values, in the same shape as an element of `GET /ext/lines`. If you need to change a field that is not in the editable list, use the [native update endpoint](/docs/?page=xai-ref-lines-update).

## Endpoint

`POST https://<your-panel-domain>/panel-api/onestream/ext/line/{uuid}/update-advanced`

## Authentication

`X-Api-Key`. `X-Auth-User` and `Authorization: Bearer` also accepted. See [Authentication](/docs/?page=panel-api-authentication).

## Required scope

`lines:write`.

## Idempotency

Optional but recommended. Pass a unique `rid` per intended change. A retried `rid` with the same body returns the cached response; a retried `rid` with a different body returns `409 Transaction already processed`.

## Path parameters

| Name | Type | Description |
| ---- | ---- | ----------- |
| `uuid` | string | The opaque line UUID. |

## Request body

At least one editable field must be present. If none are supplied, the request is rejected with `422 validation_error`.

| Field | Type | Description |
| ----- | ---- | ----------- |
| `password` | string | New line password. Reseller keys whose group has `allow_change_pass=0` receive `403 password_change_not_allowed`. |
| `expire_at` | string, int, or null | Absolute expiry. ISO 8601 with offset (`2026-12-31T00:00:00+00:00`) is canonical. A unix integer is accepted. Pass `null` to remove the expiry (make the line perpetual). Passing `0` is a validation error because the engine treats `exp_date = 0` as expired. |
| `is_enabled` | bool | Set to `false` to disable, `true` to re-enable. Truthy strings (`"true"`, `"1"`, `"yes"`, `"on"`) are also accepted. |
| `is_restreamer` | bool | Toggle the restreamer flag. |
| `max_connections` | int | Concurrent connections cap. Clamped to `[1, 100]` by the underlying handler. |
| `rid` | string | Idempotency key. |

Fields that OneStream historically allowed but this endpoint does not accept (`username`, `bouquets`, `reseller_notes`, `is_trial`) trigger the "no editable fields provided" error even when they are the only ones sent. That is intentional: silently succeeding on a rejected field is the worst possible outcome for a billing integration.

```json
{
  "password": "new-s3cret",
  "is_enabled": false,
  "max_connections": 3,
  "expire_at": "2026-12-31T00:00:00+00:00",
  "rid": "upd-user-42-2026-08"
}
```

## Response

`200 OK` with the full line object. Same shape as an element of `GET /ext/lines`.

```json
{
  "line_id": "b32c1a04-11ea-4c67-8fd1-0001000000f1",
  "username": "reseller1_20260808",
  "password": "new-s3cret",
  "expire_at": "2026-12-31T00:00:00+00:00",
  "is_enabled": false,
  "is_restreamer": false,
  "is_trial": false,
  "package_id": null,
  "bouquets": [],
  "max_connections": 3,
  "reseller_notes": "",
  "mac_addr": null,
  "owner": "billing",
  "type": "regular"
}
```

`package_id` is always `null` in the OneStream dialect (the internal API does not surface the source package on a line row). `mac_addr` is always `null` because the product does not provision physical devices.

## Examples

### cURL

```bash
curl -X POST "https://<your-panel-domain>/panel-api/onestream/ext/line/b32c1a04-11ea-4c67-8fd1-0001000000f1/update-advanced" \
  -H "X-Api-Key: <your-api-key>" \
  -H "Content-Type: application/json" \
  -d '{
    "password": "new-s3cret",
    "is_enabled": false,
    "max_connections": 3,
    "expire_at": "2026-12-31T00:00:00+00:00",
    "rid": "upd-user-42-2026-08"
  }'
```

### PHP raw

```php
$uuid = 'b32c1a04-11ea-4c67-8fd1-0001000000f1';
$ch = curl_init("https://<your-panel-domain>/panel-api/onestream/ext/line/{$uuid}/update-advanced");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'X-Api-Key: <your-api-key>',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        'password'        => 'new-s3cret',
        'is_enabled'      => false,
        'max_connections' => 3,
        'expire_at'       => '2026-12-31T00:00:00+00:00',
        'rid'             => 'upd-user-42-2026-08',
    ]),
]);
$body   = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
```

### Python raw

```python
import requests

uuid_ = "b32c1a04-11ea-4c67-8fd1-0001000000f1"
r = requests.post(
    f"https://<your-panel-domain>/panel-api/onestream/ext/line/{uuid_}/update-advanced",
    headers={"X-Api-Key": "<your-api-key>"},
    json={
        "password": "new-s3cret",
        "is_enabled": False,
        "max_connections": 3,
        "expire_at": "2026-12-31T00:00:00+00:00",
        "rid": "upd-user-42-2026-08",
    },
    timeout=30,
)
r.raise_for_status()
print(r.json())
```

## Errors

| HTTP | Error slug (or message) | When it happens | How to fix |
| ---- | ----------------------- | --------------- | ---------- |
| 401 | `Invalid API key` | Token is unknown, expired, disabled, or deleted. | Check the token or issue a new one. |
| 403 | `insufficient_scope` | Token lacks `lines:write`. | Issue a key with the scope. |
| 403 | `password_change_not_allowed` | Reseller group has `allow_change_pass=0` and the body carried `password`. | Omit `password`, or ask the panel operator to enable password changes for the group. |
| 409 | `Transaction already processed` | Same `rid` was reused with a different body. | Use a fresh `rid`, or replay with the exact original body. |
| 422 | `line_id not found or invalid` | The UUID in the URL is malformed, was not issued by this panel, or belongs to a different panel. Uniform on purpose. | Verify the UUID you stored on line-creation. |
| 422 | `update-advanced: none of the provided fields is editable by this API. Supported: password, expire_at, is_enabled, is_restreamer, max_connections.` | Body contained only rejected fields (`username`, `bouquets`, `reseller_notes`, `is_trial`), or no editable fields at all. | Send at least one editable field. Use the [native update endpoint](/docs/?page=xai-ref-lines-update) for other fields. |
| 422 | `Invalid expire_at format: expected ISO 8601 or unix timestamp` | `expire_at` is neither a parseable ISO 8601 timestamp, a positive unix integer, nor explicit `null`. | Send `2026-12-31T00:00:00+00:00`, a positive integer, or `null`. |
| 429 | `Rate limit exceeded` | The key hit its per-minute cap. | Back off and retry after `Retry-After` seconds. |
| 501 | `not_implemented` | A `GET` request was sent to this URL. | Only `POST` is accepted. |

## See also

- [Renew a line, POST /ext/line/{uuid}/renew](/docs/?page=os-ref-line-renew)
- [Enable a line, POST /ext/line/{uuid}/enable](/docs/?page=os-ref-line-enable)
- [Disable a line, POST /ext/line/{uuid}/disable](/docs/?page=os-ref-line-disable)
- [OneStream compatibility overview](/docs/?page=panel-api-onestream-compatibility)
- [Native update endpoint](/docs/?page=xai-ref-lines-update)
