Get one sub-reseller, action=get_user

Return the record of a single reseller in the classic Xtream Codes envelope. The compat layer translates this call to the native GET /panel-api/v1/resellers/{id} and wraps the result in the XC {"status": "STATUS_SUCCESS", "data": {...}} shape. The response carries the current billing snapshot in a nested billing object whose shape depends on the reseller's billing_mode (see below).

Admin keys can read any reseller. Since the panel update of 2026-09-25 a reseller key with subresellers:read can read its own sub-resellers and theirs; any other ID, including its own, answers not_found exactly like an ID that does not exist. From a reseller-side integration, call action=user_info to read the caller's own account.

Endpoint

GET https://<your-panel-domain>/panel-api/xc/{accesscode}/admin/index.php?action=get_user

The {accesscode} segment is decorative. Any non-empty value works. Security is enforced through the API key, not the path.

Authentication

Send the API key either as api_key=<your-api-key> in the query string or as Authorization: Bearer <your-api-key> in the header. Admin key, or reseller key with subresellers:read. See Xtream Codes compatibility for the full auth contract.

Required scope

resellers:read for an admin key, subresellers:read for a reseller key. A key without the scope for its type gets STATUS_NO_PERMISSIONS with insufficient_scope.

Query parameters

Name Type Required Default Description
id int yes Numeric reg-user ID of the reseller.

Response

The data payload matches the native GET /resellers/{id} shape. The billing object differs between billing modes.

For a credits-mode reseller, credits holds the current balance and both max_users and active_users are null:

{
  "status": "STATUS_SUCCESS",
  "data": {
    "id": 100260595,
    "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": null,
      "active_users": null,
      "billing_expires": null
    }
  }
}

For a users-mode reseller, credits is null, max_users is the slot cap, active_users is the current usage (own active non-trial lines plus slots already reserved by sub-resellers), and billing_expires is the Unix timestamp in seconds when the plan lapses:

{
  "status": "STATUS_SUCCESS",
  "data": {
    "id": 100295821,
    "username": "reseller_dave",
    "email": "dave@example.com",
    "member_group_id": 4,
    "member_group_name": "RESELLER",
    "status": 1,
    "billing": {
      "mode": "users",
      "credits": null,
      "max_users": 250,
      "active_users": 231,
      "billing_expires": 1793520000
    }
  }
}

HTTP status is always 200. Your client must branch on body.status, not on the HTTP code.

Examples

cURL

curl "https://<your-panel-domain>/panel-api/xc/panel_api/admin/index.php?api_key=<your-api-key>&action=get_user&id=100260595"

PHP raw

$url = 'https://<your-panel-domain>/panel-api/xc/panel_api/admin/index.php'
     . '?' . http_build_query([
         'api_key' => '<your-api-key>',
         'action'  => 'get_user',
         'id'      => 100260595,
       ]);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$body = json_decode(curl_exec($ch), true);
curl_close($ch);
if ($body['status'] !== 'STATUS_SUCCESS') {
    throw new RuntimeException($body['data']['message'] ?? 'get_user failed');
}
$reseller = $body['data'];
echo $reseller['username'], ' balance=', $reseller['billing']['credits'], PHP_EOL;

Python raw

import requests

r = requests.get(
    "https://<your-panel-domain>/panel-api/xc/panel_api/admin/index.php",
    params={"api_key": "<your-api-key>", "action": "get_user", "id": 100260595},
    timeout=30,
)
r.raise_for_status()
body = r.json()
if body["status"] != "STATUS_SUCCESS":
    raise RuntimeError(body["data"].get("message", "get_user failed"))
reseller = body["data"]
print(reseller["username"], "balance=", reseller["billing"]["credits"])

Errors

HTTP is always 200 for this dialect. The status field is the branch signal, and data.error carries the exact slug.

status Error slug When it happens How to fix
STATUS_INVALID_DATA validation_error The id parameter is missing or empty. Include a numeric id in the query.
STATUS_FAILURE invalid_key The api_key (or Authorization: Bearer) is missing, malformed, or unknown. Send a live admin key.
STATUS_NO_PERMISSIONS insufficient_scope An admin key without resellers:read, or a reseller key without subresellers:read. Issue a new key with the scope for its type. From a reseller integration, action=user_info reads the caller's own account without any scope.
STATUS_NO_PERMISSIONS sub_reseller_view_not_allowed Reseller key whose member group does not have Can Create Subresellers. Ask the panel administrator to enable it for the group.
STATUS_FAILURE not_found No reseller exists with that ID or, on a reseller key, the ID is outside the caller's sub-resellers. Verify the ID with action=get_users first.
STATUS_FAILURE rate_limited The per-key request budget for the current minute is spent. Slow the polling loop, then retry after the minute rolls over.

See also