List resellers
Return every reseller currently registered on the panel, in ascending order by numeric ID. The response is keyset-paginated with a stable next_cursor, and each row already carries the billing summary (mode, credits, slot count, active users), so the typical monthly reconciliation loop does not need a second call per reseller.
This is the endpoint your back-office code uses to walk the whole tree. It only returns direct rows from the reg_users table, so descendants of sub-resellers appear as their own top-level entries. Rebuild the hierarchy client-side from member_group_id and owner_id if you need it.
Endpoint
GET https://<your-panel-domain>/panel-api/v1/resellers
Authentication
Send the API key in the Authorization: Bearer <your-api-key> header. Only admin keys can call this endpoint. Reseller keys never receive the resellers:read scope at issuance time, so the request is rejected with insufficient_scope.
Required scope
resellers:read
Query parameters
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
limit |
int | no | 50 |
Page size. Clamped to [1, 100]. |
cursor |
int | no | 0 |
Last ID from the previous page. Rows with id > cursor are returned. |
member_group_id |
int | no | Restrict the list to a single member group (for example, only the RESELLER tier). |
|
status |
bool | no | Filter by account status. 1 returns active accounts, 0 returns disabled ones. |
|
username |
string | no | Exact username match. Case-sensitive. Useful when your billing system stores usernames and needs to resolve one to an ID before calling POST /resellers/{id}/billing/adjust. |
Response
The response is an envelope with two fields. items is the page of resellers. next_cursor is the ID to pass as cursor on the next call, or null when you have reached the last page.
active_users is populated only for resellers in users billing mode. For credits-mode resellers it is always null. created_at is a Unix timestamp in seconds, or null for historical rows migrated before that column was added.
{
"items": [
{
"id": 100234567,
"username": "reseller_alice",
"email": "alice@example.com",
"member_group_id": 4,
"member_group_name": "RESELLER",
"status": 1,
"billing_mode": "credits",
"credits": 947,
"max_users": 0,
"active_users": null,
"billing_expires": null,
"created_at": null
},
{
"id": 100295821,
"username": "reseller_bob",
"email": "bob@example.com",
"member_group_id": 4,
"member_group_name": "RESELLER",
"status": 1,
"billing_mode": "credits",
"credits": 0.25,
"max_users": 0,
"active_users": null,
"billing_expires": null,
"created_at": 1578098423
},
{
"id": 100341778,
"username": "reseller_carol",
"email": "carol@example.com",
"member_group_id": 65,
"member_group_name": "RESELLER MASTER PREMIUM",
"status": 1,
"billing_mode": "credits",
"credits": 2538,
"max_users": 0,
"active_users": null,
"billing_expires": 1783911599,
"created_at": 1579225251
}
],
"next_cursor": 100341778
}
Examples
cURL
curl -H "Authorization: Bearer <your-api-key>" \
"https://<your-panel-domain>/panel-api/v1/resellers?limit=3"
PHP SDK
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>');
$page = $client->resellers->list(limit: 50, status: true);
foreach ($page->items as $reseller) {
echo $reseller->id, ' ', $reseller->username, PHP_EOL;
}
if ($page->nextCursor !== null) {
$next = $client->resellers->list(limit: 50, cursor: (string) $page->nextCursor);
}
Python SDK
from xtream_ai_panel_api import PanelApiClient
client = PanelApiClient(base_url="https://<your-panel-domain>", token="<your-api-key>")
page = client.resellers.list(limit=50, status=True)
for reseller in page.items:
print(reseller.id, reseller.username)
if page.next_cursor is not None:
next_page = client.resellers.list(limit=50, cursor=str(page.next_cursor))
Errors
| HTTP | Error slug | When it happens | How to fix |
|---|---|---|---|
| 401 | invalid_key |
Missing, malformed, or unknown API key. | Send a live key in Authorization: Bearer <token>. |
| 403 | insufficient_scope |
The key does not carry resellers:read. Reseller keys always land here because the scope is admin-only at issuance. |
Use an admin key, or (from an integration owned by a reseller) call GET /me instead to inspect the caller's own account. |
| 429 | rate_limited |
The per-key request budget for this minute is spent. | Slow down. The default budget is 300 requests per minute; back off and retry after the minute rolls over. |