Admin Portal API Docs

PasarGuard-compatible and portal-native API reference.

Base URLs

https://admin.vsl247.com
https://admin2.vsl247.com

Authorization

Protected endpoints authenticate a portal account before checking its role.

  • Recommended: create an access token at POST /api/admin/token, then send Authorization: Bearer ACCESS_TOKEN.
  • Compatibility: /api/v1 routes also accept HTTP Basic authentication with the portal username and password.
  • The API token is valid for up to 30 days. Generate a new token after it expires.
  • The browser login session and API authentication are separate; do not send the browser session cookie as an API credential.

Quick start

1. Create a token. 2. Copy access_token. 3. Send it in the Authorization header.

curl -X POST 'https://admin.vsl247.com/api/admin/token' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  -d 'username=admin_username&password=admin_password'

curl -H 'Authorization: Bearer ACCESS_TOKEN' \
  https://admin.vsl247.com/api/users

Use a superadmin account for superadmin-only endpoints. A normal admin token is authenticated successfully but receives 403 Forbidden when its role is not allowed.

Authentication

Create a token and inspect the authenticated portal admin.

POST /api/admin/token Create a PasarGuard-style access token.

Authenticate with the portal username and password. The endpoint accepts either form data or a JSON object.

Form body
POST /api/admin/token
Content-Type: application/x-www-form-urlencoded

username=admin_username&password=admin_password
JSON body
POST /api/admin/token
Content-Type: application/json

{
  "username": "admin_username",
  "password": "admin_password"
}
Response 200
{
  "access_token": "...",
  "token_type": "bearer"
}
Use the token
curl -H 'Authorization: Bearer ACCESS_TOKEN' \
  'https://admin.vsl247.com/api/v1/me'
  • Use the exact token returned in access_token; do not include quotation marks around it.
  • Invalid credentials return 401 Unauthorized.
  • An inactive normal admin cannot receive an API token and returns 403 Forbidden.
GET /api/admin Return the authenticated admin.
Response 200
{
  "username": "admin_username",
  "is_sudo": false,
  "telegram_id": null,
  "discord_webhook": null,
  "users_usage": 0
}
HTTP Error responses Common authentication, authorization, and validation responses.
  • 400 Bad Request — the request is authenticated but a body, query parameter, or value is invalid.
  • 401 Unauthorized — credentials are missing, invalid, or the Bearer token has expired. The response includes a WWW-Authenticate header.
  • 403 Forbidden — the credentials identify a valid account, but that account's role is not allowed to use the endpoint.
  • Errors use the JSON shape {"ok": false, "error": "..."} on portal-native /api/v1 routes.

Users

Manage only the clients owned by the authenticated portal admin.

GET /api/users List owned clients with filters and pagination.
Example request
GET /api/users?offset=0&limit=10&username=client&status=active
Response 200
{
  "users": [],
  "total": 0
}
POST /api/user Create a user using the admin's remaining quota.
Request body
{
  "username": "client_username",
  "data_limit": 21474836480,
  "duration_days": 30,
  "status": "active",
  "note": "optional",
  "group_id": 1
}
Response 201
{
  "username": "client_username",
  "status": "active",
  "used_traffic": 0,
  "data_limit": 21474836480,
  "subscription_url": "https://sub.vsl247.com/sub/..."
}
Group selection group_id is optional and accepts exactly one PasarGuard group id. The legacy group, groups, and group_ids aliases remain accepted only when they resolve to one id; a list containing more than one id is rejected with 400 Bad Request. Omit it to use the admin's superadmin-assigned default group (falling back to the panel's group1 convention, or its first group, if the admin has no default configured). If it is supplied, the id must be in the admin's superadmin-assigned allowed-groups list, or the request fails with 400 Bad Request and an error naming the allowed groups; an admin with no allowed-groups list configured yet has any supplied value ignored and falls back to the default, same as omitting it.
Which group's GB this spends Every client belongs to exactly one group and spends only that group's GB balance. A group the admin holds no balance in has no GB, so creating there fails rather than falling back to another group. If the balance is too small the request fails with 400 Bad Request and an error naming the group and its remaining GB, for example Not enough remaining GB in group 'vip': 12.5 GB left, 50.0 GB requested.
GET /api/user/<username> Return one owned client.
Response 200
{
  "username": "client_username",
  "status": "active",
  "used_traffic": 1073741824,
  "data_limit": 21474836480,
  "expire": 1780000000,
  "subscription_url": "https://sub.vsl247.com/sub/..."
}
PUT /api/user/<username> Increase quota or update expiry and status.
Request body
{
  "data_limit": 32212254720,
  "expire": 1780000000,
  "status": "active"
}
Response 200
{
  "username": "client_username",
  "status": "active",
  "data_limit": 32212254720,
  "expire": 1780000000
}
Which group's GB a top-up spends Raising data_limit bills the difference to the single group the client already belongs to — the client's group is never changed by this endpoint. Existing clients were migrated to group 1. If that group's balance is too small the request fails with 400 Bad Request naming the group and its remaining GB.
DELETE /api/user/<username> Delete an owned client through the panel API.
Response 200
{
  "detail": "User successfully deleted"
}
POST /api/user/<username>/reset Reset the client's used traffic.
Request
POST /api/user/client_username/reset
Authorization: Bearer ACCESS_TOKEN
Response 200
{
  "username": "client_username",
  "status": "active",
  "used_traffic": 0,
  "data_limit": 21474836480
}
POST /api/user/<username>/revoke_sub Revoke and regenerate the subscription link.
Request
POST /api/user/client_username/revoke_sub
Authorization: Bearer ACCESS_TOKEN
Response 200
{
  "username": "client_username",
  "status": "active",
  "subscription_url": "https://sub.vsl247.com/sub/NEW_TOKEN"
}

Activity

Inspect subscription fetches and traffic usage.

GET /api/user/<username>/sub_update Return subscription fetch history.
Example request
GET /api/user/client_username/sub_update?offset=0&limit=10
Response 200
{
  "updates": [
    {
      "created_at": "2026-05-29T10:25:55Z",
      "user_agent": "v2rayNG/1.8.5"
    }
  ]
}
GET /api/user/<username>/usage Return usage records for one owned client.
Example request
GET /api/user/client_username/usage?start=2026-06-01T00:00:00Z&end=2026-06-06T00:00:00Z
Response 200
{
  "username": "client_username",
  "usages": [
    {
      "node_id": 6,
      "used_traffic": 268435456,
      "created_at": "2026-06-05T12:00:00Z"
    }
  ]
}
GET /api/users/usage Return usage records for all owned clients.
Example request
GET /api/users/usage?start=2026-06-01T00:00:00Z&end=2026-06-06T00:00:00Z
Response 200
{
  "usages": [
    {
      "username": "client_username",
      "node_id": 6,
      "used_traffic": 268435456,
      "created_at": "2026-06-05T12:00:00Z"
    }
  ]
}

Superadmin

Reporting and admin-management endpoints restricted to authenticated superadmins.

GET /api/v1/superadmin/sales Return GB sales for a time range, broken down by admin and by PasarGuard group.
What this endpoint returns Gross GB sold within the requested time window, aggregated per portal admin (admins) and per PasarGuard group (groups). This is read-only reporting: it does not modify users, quotas, or audit records.
Authentication Bearer or Basic auth Send credentials with every request.
Required role superadmin A normal admin token receives HTTP 403.
Success 200 OK Returns totals, one row per admin, and one row per group.
Access errors 401 403 Invalid credentials or insufficient role.

Query parameters

NameTypeRequiredDescriptionExample
start string or integer Required Beginning of the range, inclusive. Accepts an ISO 8601 date/time or a Unix timestamp in seconds or milliseconds. 2026-08-01T00:00:00+03:30
end string or integer Required End of the range, exclusive. It must be later than start. 2026-08-02T00:00:00+03:30
group_id integer Optional Restrict admins and totals to sales attributable to this PasarGuard group only. groups always lists every group regardless of this filter, so you can see the full breakdown either way. 2
Time range rules ISO values without a timezone are interpreted as Asia/Tehran. For predictable integrations, send an explicit offset or use UTC with Z. The interval includes start and excludes end.

Request examples

Bearer tokenRecommended
curl --get 'https://admin.vsl247.com/api/v1/superadmin/sales' \
  -H 'Authorization: Bearer SUPERADMIN_ACCESS_TOKEN' \
  --data-urlencode 'start=2026-08-01T00:00:00+03:30' \
  --data-urlencode 'end=2026-08-02T00:00:00+03:30'

--data-urlencode safely encodes the + in the timezone offset.

Basic authenticationAlternative
curl --get 'https://admin.vsl247.com/api/v1/superadmin/sales' \
  --user 'superadmin_username:superadmin_password' \
  --data-urlencode 'start=2026-08-01' \
  --data-urlencode 'end=2026-08-02'

Basic authentication is supported for /api/v1 routes. The account must still be a superadmin.

Filtered to one groupOptional
curl --get 'https://admin.vsl247.com/api/v1/superadmin/sales' \
  -H 'Authorization: Bearer SUPERADMIN_ACCESS_TOKEN' \
  --data-urlencode 'start=2026-08-01T00:00:00+03:30' \
  --data-urlencode 'end=2026-08-02T00:00:00+03:30' \
  --data-urlencode 'group_id=2'

admins and totals now cover only sales attributed to group 2; groups is unchanged and still lists every group.

Response body200 OK
{
  "ok": true,
  "range": {
    "start": "2026-07-31T20:30:00Z",
    "end": "2026-08-01T20:30:00Z",
    "start_timestamp": 1785529800,
    "end_timestamp": 1785616200,
    "end_exclusive": true,
    "naive_input_timezone": "Asia/Tehran"
  },
  "filter": {
    "group_id": null
  },
  "totals": {
    "sales_gb": 125.5,
    "new_client_gb": 100.0,
    "added_gb": 25.5,
    "new_clients": 8,
    "add_operations": 3,
    "unresolved_events": 0,
    "charged_gb": 500.0
  },
  "admins": [
    {
      "admin_id": 42,
      "username": "portal_admin",
      "is_active": true,
      "sales_gb": 55.5,
      "new_client_gb": 40.0,
      "added_gb": 15.5,
      "new_clients": 3,
      "add_operations": 2,
      "unresolved_events": 0,
      "charged_gb": 500.0
    }
  ],
  "groups": [
    {
      "group_id": 1,
      "group_name": "group1",
      "sales_gb": 90.0,
      "new_client_gb": 75.0,
      "added_gb": 15.0,
      "new_clients": 6,
      "add_operations": 2,
      "unresolved_events": 0,
      "charged_gb": 500.0,
      "has_own_pool": true,
      "quota_gb": 1000.0,
      "allocated_gb": 90.0,
      "remaining_gb": 910.0
    },
    {
      "group_id": 2,
      "group_name": "vip",
      "sales_gb": 40.0,
      "new_client_gb": 30.0,
      "added_gb": 10.0,
      "new_clients": 2,
      "add_operations": 1,
      "unresolved_events": 0,
      "charged_gb": 0.0,
      "has_own_pool": true,
      "quota_gb": 200.0,
      "allocated_gb": 40.0,
      "remaining_gb": 160.0
    },
    {
      "group_id": null,
      "group_name": "No group recorded (client predates group tracking)",
      "sales_gb": 0.0,
      "new_client_gb": 0.0,
      "added_gb": 0.0,
      "new_clients": 0,
      "add_operations": 0,
      "unresolved_events": 0,
      "charged_gb": 0.0,
      "has_own_pool": false,
      "quota_gb": null,
      "allocated_gb": null,
      "remaining_gb": null
    }
  ]
}

Response fields

FieldTypeDescription
rangeobjectNormalized UTC range and the Unix-second boundaries used by the report.
range.start, range.endstringNormalized UTC ISO 8601 values. start is inclusive; end is exclusive.
range.start_timestamp, range.end_timestampintegerUnix timestamps in seconds.
range.end_exclusivebooleanAlways true for this endpoint.
range.naive_input_timezonestringTimezone applied to ISO input without an explicit offset: Asia/Tehran.
filter.group_idinteger or nullEchoes the group_id query parameter. null when it was not supplied, meaning admins/totals cover every group.
totalsobjectCombined totals across the returned admins rows (after any group_id filter is applied).
totals.sales_gbnumberGross sales in GB: new_client_gb + added_gb.
totals.new_client_gb, totals.added_gbnumberGB assigned at client creation and GB added to existing clients.
totals.new_clients, totals.add_operationsintegerCounts of client-creation and GB-addition sale events.
totals.unresolved_eventsintegerLegacy events whose amount could not be reconstructed. Non-zero means the report is incomplete for those events.
totals.charged_gbnumberGB the superadmin handed out to admins in this window (the opposite direction of a sale). Not part of sales_gb.
admins[]arrayOne row per admin. With no group_id filter, every current admin appears, including zero-sale admins; historical deleted actors may appear as admin #ID. With group_id set, only admins with activity in that group appear.
admins[].*objectEach row contains admin_id, username, is_active, the GB totals, and the event counts.
groups[]arrayOne row per PasarGuard group that has ever had a sale or that any admin holds GB in, plus a group_id: null row for sales whose client has no group recorded. Always covers every group, independent of the group_id query filter. Sorted by sales_gb descending.
groups[].group_idinteger or nullThe PasarGuard group id, or null for sales on clients with no group recorded.
groups[].group_namestringThe group's current name from the panel, best-effort (falls back to "group {id}" if the panel is unreachable when the report runs), or the fixed no-group label for group_id: null.
groups[].charged_gbnumberGB the superadmin added to that group's balances in this window, across all admins.
groups[].has_own_poolbooleantrue when at least one admin holds GB in this group. false means nobody can currently sell there.
groups[].quota_gb, groups[].allocated_gb, groups[].remaining_gbnumber or nullCurrent standing of that group's balances, summed over every admin holding one: total GB, GB already allocated to clients, and GB still sellable. All three are null when has_own_pool is false. These describe the balance right now — unlike the sales figures, they are not scoped to the requested time range.
groups[].*objectSame GB sales totals and event counts as admins[], scoped to that group.

Sales calculation

sales_gb = new_client_gb + added_gb The report uses client-creation and GB-addition audit events. Deleted users or later quota changes do not retroactively remove the original sale event.
Group attribution Each sale is attributed to the client's single stored group. Existing clients were pinned to group 1 by migration; changing an admin's default group affects only clients created afterwards. The group_id: null bucket remains only as a defensive fallback for malformed or externally imported records.
Charges vs. sales charged_gb tracks GB flowing into an admin's balance (the superadmin topping them up), while sales_gb tracks GB flowing out to clients. They are reported side by side but never summed together. Unlike sales, a charge is never split across groups: it always names the exact group whose balance it credited.

Validation errors

StatusWhen it happensExample body
400 Bad RequestMissing or malformed time values, a non-positive range, or an out-of-range timestamp.{"ok": false, "error": "end must be later than start"}
401 UnauthorizedCredentials are missing, invalid, or an access token has expired.{"detail": "Not authenticated"}
403 ForbiddenThe credentials are valid, but the account is not a superadmin. A normal admin token receives HTTP 403 here.{"detail": "Insufficient role"}
Authorization behavior Authentication and role checks happen before the report is generated. A normal admin token or Basic-auth account cannot read another admin's sales.
PATCH /api/v1/admins/{admin_id} Charge an admin, reduce quota, or update admin settings.
What this endpoint does Updates a portal admin selected by admin_id. Quota changes are write operations and are recorded in the superadmin audit log.
Authentication Bearer or Basic auth Send credentials with every request.
Required role superadmin Normal admin accounts receive 403.
Request body JSON object Send one or more supported fields.
Success 200 OK Returns {"ok": true}.

Path parameter

NameTypeRequiredDescription
admin_idintegerRequiredID of the portal admin to update. Get IDs from GET /api/v1/admins.

Quota actions

FieldTypeRequiredEffectRules
add_gb number Optional Charges the admin by adding this much GB to one group's balance. Must be greater than 0. It does not directly change any client allocation. Lands in the admin's primary group unless group_id names another.
reduce_gb number Optional Takes this much GB out of one group's balance. Must be greater than 0. The balance cannot drop below the GB already allocated to clients in that group. Applies to the admin's primary group unless group_id names another.
group_id integer Optional Chooses which group's balance add_gb / reduce_gb moves. Charging a group the admin holds no GB in opens a balance there. Reducing a group they hold no GB in is rejected. Omitted, it means the admin's primary group — which is where a request that never mentions groups has always put the GB.
group_quotas array Optional Sets pool sizes outright (rather than adding to them). Each entry is {"group_id": 1, "quota_gb": 1000}. Sending "quota_gb": null removes that group's balance entirely, which is only allowed once no clients remain in it. A balance cannot be set below the GB already allocated in that group.
Safe reduction rule A group's balance can never drop below the GB already allocated to clients in that group. If 80 GB is allocated in group1, that group's balance cannot be reduced below 80 GB, and the API rejects a reduction that would violate this.
GB is held per group An admin's GB lives in a separate balance per PasarGuard group — 1000 GB in group1 and 200 GB in group2 at the same time — and nothing is shared between them: spending group1 never touches group2, and a group the admin holds no balance in has no GB at all. Requests that never mention a group keep working exactly as before, because they act on the admin's primary group (group1 by default), which is where their GB already was.

Other supported updates

FieldTypeEffect
is_activebooleanActivate or deactivate the admin account.
min_client_gbnumberSet the minimum GB allowed when the admin creates a client; must be greater than 0.
subscription_hoststringSet the subscription hostname, such as sub.example.com.
hide_brandingbooleanEnable or disable branded subscription output.
portal_passwordstringChange the portal login password.
marzban_username, marzban_passwordstringUpdate the linked panel credentials; the credentials are validated before saving.

Request examples

Charge 25 GBQuota increase
curl -X PATCH 'https://admin.vsl247.com/api/v1/admins/42' \
  -H 'Authorization: Bearer SUPERADMIN_ACCESS_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"add_gb": 25}'
Reduce 10 GBQuota decrease
curl -X PATCH 'https://admin.vsl247.com/api/v1/admins/42' \
  -H 'Authorization: Bearer SUPERADMIN_ACCESS_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"reduce_gb": 10}'
Charge 100 GB into one group's poolPer-group
curl -X PATCH 'https://admin.vsl247.com/api/v1/admins/42' \
  -H 'Authorization: Bearer SUPERADMIN_ACCESS_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"add_gb": 100, "group_id": 2}'

Only group 2's balance grows by 100 GB; every other group is untouched.

Set pool sizes directlyPer-group
curl -X PATCH 'https://admin.vsl247.com/api/v1/admins/42' \
  -H 'Authorization: Bearer SUPERADMIN_ACCESS_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"group_quotas": [
        {"group_id": 1, "quota_gb": 1000},
        {"group_id": 2, "quota_gb": 200},
        {"group_id": 3, "quota_gb": null}
      ]}'

Group 1 is set to 1000 GB, group 2 to 200 GB, and group 3's balance is removed so the admin can no longer sell there.

Response body200 OK
{
  "ok": true
}

Errors

StatusWhen it happensExample
400 Bad RequestThe body is not a JSON object, a GB value is missing/invalid/non-positive, the admin does not exist, or a reduction would go below the GB allocated in that group.Cannot reduce below the 80.0 GB already allocated in that group
400 Bad Requestreduce_gb named a group_id the admin holds no GB in, or a group_quotas entry would remove a balance that still has clients in it.This admin has no GB pool for that group
401 UnauthorizedCredentials are missing, invalid, or expired.{"ok": false, "error": "Authentication required"}
403 ForbiddenThe credentials are valid, but the account is not a superadmin.{"ok": false, "error": "Forbidden"}
Recommended usage Send exactly one mutation per request. A request may add GB, reduce GB, replace a group_quotas batch, or change one admin setting. Mixing mutations is rejected before anything changes. Every group_quotas entry is validated first and the complete batch commits or rolls back together.

Portal-Native API

Legacy routes that use the portal's ok response wrapper.

GET /api/v1/me Return the current portal account and quota.
Response 200
{
  "ok": true,
  "user": {
    "username": "admin_username",
    "role": "admin",
    "quota_bytes": 107374182400,
    "remaining_bytes": 85899345920,
    "group_ids": [1, 2],
    "default_group_id": 1,
    "group_quotas": [
      {
        "group_id": 1,
        "group_name": "group1",
        "quota_gb": 1000.0,
        "allocated_gb": 90.0,
        "remaining_gb": 910.0,
        "quota_bytes": 1073741824000,
        "allocated_bytes": 96636764160,
        "remaining_bytes": 977105059840
      }
    ]
  }
}
Reading the quota fields quota_bytes / remaining_bytes are the account-wide totals across every group, kept for compatibility — they are a sum, not a balance anything is spent from. group_quotas is where the real balances are: one entry per group the admin holds GB in. A group missing from that list has no GB, so the admin cannot create clients in it. For an admin who only ever sells in one group, the single entry there equals the account totals.
GET /api/v1/clients Return the portal-native client list.
Example request
GET /api/v1/clients?page=1&per_page=10&search=client&live=1
Response 200
{
  "ok": true,
  "page": 1,
  "per_page": 10,
  "total": 1,
  "has_next": false,
  "clients": []
}
POST /api/v1/clients Create a client using the portal-native response wrapper.
Request body
{
  "username": "client_username",
  "data_limit_gb": 20,
  "duration_days": 30,
  "group_id": 1
}
Response 201
{
  "ok": true,
  "client": {
    "username": "client_username",
    "status": "active",
    "data_limit": 21474836480,
    "subscription_url": "https://sub.vsl247.com/sub/..."
  }
}
Group selection group_id is optional and accepts exactly one PasarGuard group id. The legacy group, groups, and group_ids aliases remain accepted only when they resolve to one id; multiple ids are rejected with 400 Bad Request. Omit it to use the admin's superadmin-assigned default group (falling back to the panel's group1 convention, or its first group, if the admin has no default configured). If it is supplied, the id must be in the admin's superadmin-assigned allowed-groups list, or the request fails with 400 Bad Request and an error naming the allowed groups; an admin with no allowed-groups list configured yet has any supplied value ignored and falls back to the default, same as omitting it.
Which group's GB this spends Every client belongs to exactly one group and spends only that group's GB balance. A group the admin holds no balance in has no GB, so creating there fails rather than falling back to another group. If the balance is too small the request fails with 400 Bad Request and an error naming the group and its remaining GB, for example Not enough remaining GB in group 'vip': 12.5 GB left, 50.0 GB requested.
POST /api/v1/admins Create a portal admin and link a non-sudo panel admin.
Request body
{
  "username": "portal_admin",
  "portal_password": "portal-password",
  "quota_gb": 100,
  "min_client_gb": 0.5,
  "subscription_host": "sub.example.com",
  "marzban_admin_mode": "existing",
  "marzban_username": "panel_admin",
  "marzban_password": "panel-password",
  "group_ids": [1, 2],
  "default_group_id": 1,
  "group_quotas": [
    {"group_id": 1, "quota_gb": 1000},
    {"group_id": 2, "quota_gb": 200}
  ]
}
Response 201
{
  "ok": true,
  "admin_id": 42
}
Group assignment group_ids (optional; accepts a single id or a list, alias groups) is the set of PasarGuard groups this admin is allowed to create clients in. Omit it, or leave it empty, to leave the admin unrestricted-by-list: their client-creation requests can't pick a group and always fall back to the default described below. default_group_id (optional) is the group used when the admin's own client-creation request doesn't specify one; it must be one of group_ids if that list is non-empty, or the request fails with 400 Bad Request. Leave it unset to fall back to the panel's group1 convention (or its first group). Both can be changed later from the superadmin web UI's per-admin "Allowed groups" panel; there is currently no API route to update an existing admin's group assignment.
Per-group GB pools quota_gb opens the admin's balance in their primary group — default_group_id if given, otherwise group1. group_quotas (optional) funds each group it lists; an entry for the primary group replaces quota_gb rather than adding to it. With the body above the admin can sell 1000 GB into group 1 and 200 GB into group 2 independently, with nothing shared between them. Each entry needs both group_id and quota_gb. A group left out has no GB, so the admin cannot create clients in it. Omitting the field entirely produces an admin who sells only in their primary group, which is exactly what this endpoint has always created. Balances can be added, resized, or removed afterwards with PATCH /api/v1/admins/{admin_id}.

No matching endpoints.

Compatibility Notes

  • PasarGuard-compatible routes manage only clients owned by the authenticated portal admin.
  • Client creation and data-limit increases follow portal quota rules.
  • An admin's GB is held separately per PasarGuard group and is never shared between them. Every client belongs to exactly one group, and creating or topping it up bills only that group's balance. Existing clients are pinned to group 1; changing the admin default affects only new clients.
  • Deleting a user never returns quota to the admin.
  • PasarGuard-compatible responses do not use the portal-native ok wrapper.
  • Unsupported panel administration and system routes are not proxied.