Skip to content

Users and data lifecycle

Use this guide after the reseller quickstart. These allocation endpoints manage virtual child quotas, not independent purchased data. Use invoices for a purchase and the accounting model to choose between them.

POST /users requires a unique username and an account password. Email is optional. Omitting is_top_level creates a sub-user under the caller; only a superuser can create an independent account with is_top_level: true. Sub-users cannot create another generation of managed users.

Create identity first, persist its returned id, then provision the selected package. You can send package_id and positive data at creation to assign an initial shared quota, but the parent must already own that package’s root order. The separate two-step quickstart makes failures and retries easier to reconcile.

Use GET /users with the documented filters to find managed customers, GET /users/{id} for one account, and GET /users/{id}/orders for its package orders. The last operation includes inactive orders; it is not proof that every returned order is usable. Follow pagination.

A user can have orders for several packages. Data allowances, usage, ledger buckets, and proxy credentials belong to each order, not to a single user-wide traffic balance. The user response includes an orders array; it is empty until the user has an order. Use package_id to select the product when buying data, allocating a quota, or rotating that package’s proxy password.

Your local customer ID does not replace the API UUID. Store a mapping; optional meta accepts bounded, non-sensitive correlation values, not secrets or an arbitrary nested customer document.

Both allocation operations require this body shape:

{
"package_id": "{package_id}",
"data": 1073741824
}

POST /users/{id}/data/add adds these bytes to total assigned data. It returns 202 with the updated order. It creates a child order if absent; it rejects an existing independently purchased order. The caller must own both the sub-user and the matching root order.

DATA INPUT HELPER

Convert allocation units to bytes

API UNIT: BYTES
Send this integer1073741824

Binary and decimal units are shown separately so the allocation is explicit.

If a child has 10 GiB assigned and has used 3 GiB, adding 5 GiB produces 15 GiB assigned, 3 GiB used and 12 GiB remaining. It does not set remaining data to 5 GiB. The parent’s purchased pool is unchanged until traffic uses it.

The official SDK handles short transient failures during the call. If the final result is uncertain, read the child’s order and compare its assigned total before sending another increment. See retries and recovery.

This removes 2 GiB from the assigned ceiling. Fill the placeholders from your stored mapping and record the expected new assigned total before sending the request.

RequestPOST /users/{user_id}/data/subtract
curl --request POST 'https://{api_host}/api/v1/users/{user_id}/data/subtract' \
--header 'Authorization: Static {api_key}' \
--header 'Content-Type: application/json' \
--data '{
"package_id": "{package_id}",
"data": 2147483648
}'
Response202 Accepted

Selected fields

{
"id": "550e8400-e29b-41d4-a716-446655440003",
"package": {
"id": "550e8400-e29b-41d4-a716-446655440002"
},
"data": 8589934592,
"data_remaining": 5368709120,
"data_spent": 3221225472,
"ledgers": []
}
Show full responseShow selected fields
{
"id": "550e8400-e29b-41d4-a716-446655440003",
"is_auto_renewal": false,
"auto_renewal_percentage": 0,
"auto_renewal_data": 0,
"package": {
"id": "550e8400-e29b-41d4-a716-446655440002",
"name": "Residential example",
"alias": "elite",
"is_unlimited_data": false,
"targeting_options": {
"package": "package",
"split_char": "-",
"value_char": "-",
"continent": "continent",
"country": "country",
"region": "region",
"city": "city",
"asn": "asn",
"isp": "isp",
"username": "username",
"pool": "pool",
"location": "location",
"location_format": "",
"session": "sid",
"session_mode_tag": "",
"session_ttl": "ttl",
"session_ttl_format": 1,
"os": "os",
"os_combined": false,
"os_split_char": "-",
"os_linux": "linux",
"os_windows": "windows",
"os_ios": "ios",
"os_macos": "macos",
"os_android": "android"
}
},
"proxy_password": "example-proxy-password",
"proxy_password_reset": null,
"pools": [],
"data": 8589934592,
"data_remaining": 5368709120,
"data_spent": 3221225472,
"ledgers": [],
"latest_data_top_up": 0,
"latest_data_top_up_date": null,
"data_updated": "2026-09-16T12:00:00Z",
"updated": "2026-09-16T12:00:00Z",
"created": "2026-09-16T12:00:00Z"
}

Replace placeholders in braces with your values. Responses use synthetic example data.Install SDKsAPI reference →

Expect 202. From 10 GiB assigned and 3 GiB used, the result is 8 GiB assigned and 5 GiB remaining. data_spent is unchanged. This is not a money refund, and no bytes are credited to the parent.

The amount must be positive and cannot exceed total assigned data. The validation is against the assigned ceiling, not the unspent balance. It can therefore reduce the ceiling below historical usage; REST remaining is then clamped to zero.

For finite virtual orders, reducing the quota to or below consumed data exhausts the personal allowance. Other children can continue if the shared pool remains usable. For example, 10 GiB assigned minus a 7 GiB reduction, with 3 GiB already used, leaves no personal allowance. Adding 5 GiB later leaves 8 GiB assigned, 3 GiB used and 5 GiB remaining.

Traffic and other changes can occur between a read and a write. Serialize your own quota operations, record the exact deltas and re-read the result; there is no public atomic “set remaining balance” operation. If the child is already over its ceiling, first account for that deficit when calculating a desired new remaining allowance.

If the shared pool is empty or expired, refill the parent’s purchased order instead. Increasing only the child’s quota cannot supply missing traffic. After any recovery, check the returned balance and perform a bounded connectivity test once accounting/cache updates are visible.

Order PATCH /orders/{id} changes only the documented auto-renewal settings, not an arbitrary allowance or expiration. Send both settings as zero to disable; see billing and renewal boundaries. For an allowed order, POST /reset-password selects order_id and returns a success message; re-read or regenerate credentials to obtain the new secret.

TaskOperation and outcome
Edit customer details or access policyPATCH /users/{id} with documented fields such as first_name, allowed_ips, blocked_domains or meta; use the current ETag with If-Match
Rotate a customer’s proxy passwordPOST /users/{id}/password; send package_id, observe cooldown errors, then regenerate and securely deliver credentials
Inspect package accessGET /users/{id}/orders; match by package UUID, not list position
Remove a virtual orderDELETE /orders/{id} within the allowed account scope; destructive, does not refund the assigned quota into the parent pool
Remove the customerDELETE /users/{id}; stop new commercial activity and retain required local accounting mappings before removal

Passwords for dashboard login and proxy access are different. A password rotation is not a temporary suspension; old delivered proxy credentials need replacement. See account security.

Do not use deletion as a billing correction. Independently purchased sub-user orders also have legacy deletion-side counter behavior that is not a guaranteed usable-ledger refund. Preserve invoice, order and operation records for reconciliation.

Data-add does not reset data_spent, create a new month, or renew a parent ledger. Decide whether your plan grants additional bytes, resets an allowance, or buys an independent expiring bucket. Keep that policy in your billing system and describe it to customers. Review ledger expiration before promising rollover.