Disable a line
If you are starting a new integration instead of migrating an existing one, prefer the native v1 API with the official SDKs. The XC dialect keeps compatibility with legacy tooling; the native dialect gives you typed models, header-based idempotency, and structured HTTP status codes.
action=disable_line flips the reseller-visible enabled flag on a subscriber line to false. The request is translated to the native POST /panel-api/v1/lines/{id}/disable and rewrapped in the classic {"status": "STATUS_SUCCESS", "data": {...}} envelope. The change is instantaneous; active connections keep playing until the client reconnects, then the panel refuses them.
Two flags govern whether a line serves traffic:
enabledis the reseller-visible toggle.enable_lineanddisable_linemove it.admin_enabledis the admin override. If it isfalse, the line stays blocked no matter whatenabledsays. Onlyedit_lineon an admin key can change it.
Disable does not:
- Charge credits. It is always free, in every billing mode, on both admin and reseller keys.
- Refund credits already spent. Credits paid to create or extend the line stay spent.
- Delete the line. The row and its bouquets stay in the database. Re-enable with
enable_lineor delete definitively withdelete_line. - Free the slot in
usersbilling mode. The slot count is based on line existence, not on theenabledflag. To free a slot,delete_lineis required.
Endpoint
POST https://<your-panel-domain>/panel-api/xc/{accesscode}/admin/index.php?action=disable_line
Both /admin/index.php and /reseller/index.php are accepted. The admin-versus-reseller decision comes from the key.
Authentication
Any one of these three forms:
?api_key=<your-api-key>in the query string.api_key=<your-api-key>in the POST body form field.Authorization: Bearer <your-api-key>HTTP header.
See Authentication.
Required scope
lines:write.
Idempotency
Optional. Pass rid=<unique-per-operation> to opt in. Disable is naturally idempotent (twice-disabled stays disabled), so the practical benefit is limited to replaying the response payload. See the idempotency section.
Request body
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id |
int | yes | The line to disable. | |
rid |
string | no | Idempotency identifier. |
Response
data is the full Line object with enabled=false. Same shape used by action=get_line.
{
"status": "STATUS_SUCCESS",
"data": {
"id": 172511994,
"username": "u_a1b2c3d4",
"password": "Sup3rSecret1",
"member_id": 100,
"exp_date": 1849365538,
"max_connections": 3,
"is_trial": false,
"is_restreamer": false,
"enabled": false,
"admin_enabled": true,
"bouquets": [2, 4],
"created_at": 1786207138
}
}
HTTP status is always 200, even on failure.
Examples
cURL
curl -X POST "https://<your-panel-domain>/panel-api/xc/panel_api/admin/index.php?api_key=<your-api-key>&action=disable_line" \
-d "id=172511994" \
-d "rid=dis-172511994-2026-01-15"
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' => 'disable_line']);
$body = http_build_query([
'id' => 172511994,
'rid' => 'dis-172511994-' . bin2hex(random_bytes(8)),
]);
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $body,
]);
$resp = json_decode(curl_exec($ch), true);
curl_close($ch);
if (($resp['status'] ?? '') !== 'STATUS_SUCCESS') {
throw new RuntimeException($resp['data']['message'] ?? 'disable_line failed');
}
Python (raw HTTP)
import requests, secrets
r = requests.post(
"https://<your-panel-domain>/panel-api/xc/panel_api/admin/index.php",
params={"api_key": "<your-api-key>", "action": "disable_line"},
data={
"id": 172511994,
"rid": f"dis-172511994-{secrets.token_hex(8)}",
},
timeout=30,
)
r.raise_for_status()
body = r.json()
if body.get("status") != "STATUS_SUCCESS":
raise RuntimeError(body["data"].get("message", "disable_line failed"))
Errors
Response is always HTTP 200. Branch on status, then data.error.
| status | Error slug | When it happens | How to fix |
|---|---|---|---|
STATUS_INVALID_DATA |
validation_error |
id 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_NO_PERMISSIONS |
insufficient_scope |
The key does not have lines:write. |
Grant the scope. |
STATUS_FAILURE |
idempotency_conflict |
Same rid reused with a different body. |
Pick a new rid. |
STATUS_FAILURE |
idempotency_in_flight |
Same rid is still processing. |
Retry after a moment. |
STATUS_FAILURE |
invalid_key |
Token missing, unknown, disabled, expired, or IP not in allow-list. | Verify the token and the IP allow-list. |
STATUS_FAILURE |
rate_limited |
Per-minute cap or per-IP cap exceeded. | Back off. |
STATUS_FAILURE |
api_disabled |
Panel API is switched off. | Contact the panel admin. |