---
title: "Delete a line"
description: "Permanently delete a line and cascade-clean its bouquet assignments and contact info. Never refunds credits."
---

# Delete a line

Permanently delete a line. Related rows (bouquet assignments in `user_bouquets`, and contact info in `admin_user_contact_info` / `reseller_user_contact_info`) are cleaned up in the same operation, so no orphan rows are left behind.

Deletion does **not** refund credits, matching the panel UI. In `users` billing mode the slot is released automatically because the active-users count reads live from the users table.

Reseller keys are subject to the `member_groups.delete_users` permission: if the reseller's group is not allowed to delete customers, the endpoint returns `403 delete_not_allowed`. This mirrors the guard the reseller UI applies, so a POST from an API integration cannot bypass what the UI itself would block.

The response has a **compact shape**, not the full line object: just `{id, username, deleted}`. Use it to confirm the row is gone before you take a follow-up action in your billing system.

## Endpoint

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

## Authentication

Bearer token in the `Authorization` header. See [Panel API authentication](/docs/?page=panel-api-authentication).

## Required scope

`lines:write`.

## Idempotency

Required. Send an `Idempotency-Key` header on every call. Retrying the same key returns the cached response; a missing header returns `400 missing_idempotency_key`. A retry of the same delete after the row is gone (with the same idempotency key) returns the original `deleted: true` payload, not a `404`.

## Path parameters

| Name | Type | Description |
| ---- | ---- | ----------- |
| `id` | int | The line id to delete. |

## Request body

Empty. Send an empty JSON body `{}` (or no body at all).

## Response

`200 OK` with the compact shape:

```json
{
  "id": 172504297,
  "username": "u_a1b2c3d4",
  "deleted": true
}
```

The panel confirms the row is gone before responding with `deleted: true`. If the underlying cascade left the row in place for any reason, the endpoint returns `500 delete_failed` and the row is not reported as deleted.

## Examples

### cURL

```bash
curl -X POST https://<your-panel-domain>/panel-api/v1/lines/172504297/delete \
  -H "Authorization: Bearer <your-api-key>" \
  -H "Idempotency-Key: line-172504297-delete-2026-08-08"
```

### 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>');

// delete returns a bool: true once the panel confirms the row is gone.
$deleted = $client->lines->delete(
    id:             172504297,
    idempotencyKey: 'line-172504297-delete-2026-08-08',
);
echo $deleted ? 'gone' : 'still there', PHP_EOL;
```

### Python SDK

```python
from xtream_ai_panel_api import PanelApiClient

client = PanelApiClient(base_url="https://<your-panel-domain>", token="<your-api-key>")

# delete returns a bool: True once the panel confirms the row is gone.
deleted = client.lines.delete(
    id=172504297,
    idempotency_key="line-172504297-delete-2026-08-08",
)
print(deleted)  # True
```

## Errors

| HTTP | Error slug | When it happens | How to fix |
| ---- | ---------- | --------------- | ---------- |
| 400 | `missing_idempotency_key` | The `Idempotency-Key` header was not sent. | Send a per-intent key on every write. |
| 401 | `invalid_key` | Token is unknown, expired, disabled, or deleted. | Check the token or issue a new one. |
| 403 | `delete_not_allowed` | Reseller group has `delete_users=0`. | Change the setting on the member group, or call from an admin key. |
| 403 | `insufficient_scope` | Token lacks `lines:write`. | Issue a key with the scope. |
| 404 | `not_found` | The line id does not exist (never did, or was already deleted with a different idempotency key), or a reseller key targeted a line it does not own. | Verify the id and ownership. |
| 409 | `idempotency_conflict` | Same key was reused with a different body. | Use a fresh key. |
| 409 | `idempotency_in_flight` | Same key is still processing. | Retry after a moment. |
| 429 | `rate_limited` | The key hit its per-minute cap. | Back off and retry after `Retry-After` seconds. |
| 500 | `delete_failed` | The cascade did not remove the row (deadlock, permission issue). | Retry with a fresh key; if it persists, contact support. |

## See also

- [Disable a line](/docs/?page=xai-ref-lines-disable) (soft off, no deletion)
- [Create a line](/docs/?page=xai-ref-lines-create)
- [Panel API lines overview](/docs/?page=xai-ref-lines-list)
