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).

Only admin API keys can call this action. Reseller keys are rejected before the handler runs because they never receive resellers:read at issuance. From a reseller-side integration, call action=user_info instead to introspect 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 only. See Xtream Codes compatibility for the full auth contract.

Required scope

resellers:read. Reseller keys never carry this scope, so a reseller-issued key always sees 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 The key does not carry resellers:read. Reseller-issued keys always land here. Use an admin key, or call action=user_info from a reseller integration to introspect the caller's own account.
STATUS_NO_PERMISSIONS admin_only_endpoint A key that carried the scope but is still tagged as a reseller reached the handler. Use an admin key.
STATUS_FAILURE not_found No reseller exists with that ID. 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