GET /ext/user/find
/ext/user/find returns sub-resellers under the calling key. Its main use is looking up a specific sub-reseller by name before a follow-up call to /ext/user/{id}/update or /ext/user/{id}/credit. Called without a filter, it returns the full list.
The endpoint maps to the panel's resellers listing under the hood. In OneStream terminology the field name for the filter is name; the dialect translates it to username for the v1 API. The response objects carry the same shape the native /panel-api/v1/resellers endpoint returns, without the {"items": ...} envelope.
Endpoint
GET https://<your-panel-domain>/panel-api/onestream/ext/user/find
Authentication
Send the API key in X-Api-Key, X-Auth-User, or Authorization: Bearer. See the OneStream overview.
Required scope
resellers:read. Reseller keys typically do not carry this scope, so this endpoint is normally reachable only by admin keys.
Query parameters
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
name |
string | no | (none) | Exact-match filter on the sub-reseller's username. Case-sensitive. Translated internally to username. |
If name is omitted, the endpoint returns the full paginated first page of sub-resellers the calling key can see. To list beyond the first page, use the native GET /panel-api/v1/resellers?cursor=<value> endpoint. The OneStream dialect does not project a cursor into this response.
Response
A plain JSON array. Each element has the following fields (a subset of the native resellers shape, kept identical for compatibility).
| Field | Type | Description |
|---|---|---|
id |
int | Numeric sub-reseller id. Pass this as {id} in /ext/user/{id}/update and /ext/user/{id}/credit. |
username |
string | Sub-reseller username. |
email |
string | Sub-reseller email. May be empty. |
member_group_id |
int | Id of the member group this sub-reseller belongs to. |
member_group_name |
string | Human-readable name of the member group. |
status |
int | 1 when the sub-reseller is enabled, 0 when disabled. |
billing_mode |
string | Either "credits" or "users". Decides how the sub-reseller pays for new lines. |
credits |
float | Credit balance, when billing_mode == "credits". 0 otherwise. |
max_users |
int | Line cap, when billing_mode == "users". 0 otherwise. |
active_users |
int or null | Currently active non-trial lines counted against max_users. null in credits mode. |
billing_expires |
int or null | Unix epoch when the sub-reseller's subscription expires. null means no expiry. |
created_at |
int or null | Unix epoch when the sub-reseller was created. May be null for legacy accounts imported before the field was populated. |
Example response for ?name=reseller1:
[
{
"id": 50,
"username": "reseller1",
"email": "reseller1@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
}
]
Example response for a name that does not match anyone:
[]
Examples
cURL
curl -H "X-Api-Key: <your-api-key>" \
"https://<your-panel-domain>/panel-api/onestream/ext/user/find?name=reseller1"
PHP raw
$name = 'reseller1';
$url = 'https://<your-panel-domain>/panel-api/onestream/ext/user/find?name=' . urlencode($name);
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-Api-Key: <your-api-key>']);
$rows = json_decode(curl_exec($ch), true);
curl_close($ch);
if ($rows === []) {
echo "no match\n";
} else {
foreach ($rows as $r) {
echo $r['id'] . ' ' . $r['username'] . ' (' . $r['credits'] . " credits)\n";
}
}
Python raw
import requests
r = requests.get(
"https://<your-panel-domain>/panel-api/onestream/ext/user/find",
headers={"X-Api-Key": "<your-api-key>"},
params={"name": "reseller1"},
timeout=30,
)
r.raise_for_status()
rows = r.json()
if not rows:
print("no match")
else:
for row in rows:
print(row["id"], row["username"], row["credits"])
Errors
| HTTP | Error slug | When it happens | How to fix |
|---|---|---|---|
| 401 | invalid_key |
Header is missing, the token is unknown, the key was disabled, expired, deleted, or the caller IP is not on the key's IP allow-list. | Check the header. If the key was rotated, mint a new one from the panel. |
| 403 | insufficient_scope |
The key does not carry resellers:read. Reseller keys typically hit this. |
Use an admin key, or regenerate the key with resellers:read. |
| 429 | rate_limited |
The per-key or per-IP rate limit was hit. Response carries Retry-After and X-RateLimit-* headers. |
Back off for the number of seconds in Retry-After. |
| 403 | api_disabled |
An admin has turned the Panel API off for this panel. | Ask the admin to re-enable it. |
See also
- OneStream overview
- Native resellers listing with cursor pagination.
- OneStream sub-reseller writes for create, update, and credit adjustments.