Root order
The package purchase owned by the main user. It owns every data ledger for that user/package pair and is the parent of reseller-created child orders.
ProxyRequest accounts traffic in integer bytes. A reseller integration must distinguish the physical byte pool owned by a root order from the commercial limit assigned to each sub-user. They change during the same request, but they are not the same balance.
Binary and decimal units are shown separately so the allocation is explicit.
Root order
The package purchase owned by the main user. It owns every data ledger for that user/package pair and is the parent of reseller-created child orders.
Data ledger
A physical pool with total bytes, remaining bytes, and an optional expiry. Only root orders own ledgers.
Active ledger
The one ledger currently used by proxy authentication and accounting. A child order points to the same active ledger as its parent.
Child order
A sub-user’s independently assigned limit. Its data and data_spent
fields enforce that customer limit without creating another physical pool.
remaining = 3 GB − data_spentremaining = 5 GB − data_spentBoth consume the active parent ledger. Their assigned limits do not reserve bytes from that ledger.
The proxy counts transferred bytes while it handles HTTP requests, CONNECT tunnels, SOCKS5 TCP streams, and UDP traffic. For metered packages, it aggregates positive byte deltas with the consuming user, order, package, and active ledger identifiers before sending them to accountant.
Accountant applies each batch to two projections:
data_ledgers.data_remaining = data_ledgers.data_remaining - bytesorders.data_spent = orders.data_spent + bytesThe ledger update is grouped by ledger_id; the order update is grouped by the order that actually generated traffic. This is what makes root and sub-user accounting behave differently.
| Traffic owner | Physical balance that decreases | data_spent that increases | Personal remaining balance |
|---|---|---|---|
| Main user | Root order’s active ledger | Root order | Not separately calculated |
| Sub-user | Parent root order’s active ledger | That sub-user’s child order | child.data - child.data_spent |
| Unlimited package | No byte-ledger decrement | Traffic is still captured for analytics | Not byte-enforced |
Assume the active parent ledger starts with 10 GB. Sub-user A is assigned 3 GB and consumes 1.2 GB; sub-user B is assigned 5 GB and consumes 0.8 GB.
Parent active ledger: 10.0 - 1.2 - 0.8 = 8.0 GB remainingSub-user A: 3.0 - 1.2 = 1.8 GB remainingSub-user B: 5.0 - 0.8 = 4.2 GB remainingParent order data_spent = 0 GBThe parent order’s own data_spent stays unchanged because the child orders were the consumers. The shared parent ledger still pays for both. Direct traffic made with the parent’s credentials would increment the parent order’s data_spent as well as decrement the same ledger.
POST /users/{id}/data/add and the matching subtract operation change the child order’s data allowance. They do not decrement the parent ledger, create a child ledger, or reserve bytes from the shared pool.
This makes overcommit possible: the sum of all child limits can be greater than the bytes currently available across parent ledgers. It is useful when not every customer consumes their full allowance, but your billing system should monitor both values:
Subtracting allocation cannot remove more than the child order’s current assigned data. It also synchronizes that child to the parent’s current active ledger when necessary.
A root order can keep more than one valid ledger. This lets separate purchases retain their own expiry and lets accountant move the whole order tree without rebuilding credentials.
active_ledger becomes empty for the whole tree and metered proxy access cannot continue.A ledger is eligible as a replacement only when it belongs to the root order, is not marked expired, has data_remaining > 0, and has no expiry or an expiry in the future. Created time and ledger ID provide deterministic FIFO ordering between eligible replacements.
| Condition | Accountant action | Who loses access | Event meaning |
|---|---|---|---|
| Active ledger remains above zero | Keep the current ledger | Nobody | user.data.change reports its latest remaining bytes |
| Active ledger reaches zero or below | Expire it and transition the whole tree | Nobody if a replacement exists; otherwise root and children | user.data.run_out identifies the exhausted ledger |
| Finite child limit reaches zero or below | Clear only that child order’s active ledger and invalidate its cache | That sub-user only | order.data.run_out reports the child limit exhaustion |
| Ledger expires by time | Run the same whole-tree transition | Depends on replacement availability | Expiry and byte run-out share the transition model |
Usage is processed in batches, so a balance can cross zero rather than stop exactly at zero. Both webhook order.data and order.data_remaining can therefore be negative and represent overdraft from the final batch.
order.data
Remaining bytes in the ledger named by order.ledger_id after the usage
batch. It describes the shared physical pool, even when a child user
generated the traffic.
order.data_remaining
Remaining bytes in a finite child order. It is null for root and unlimited
orders; null does not mean zero.
Webhooks are optimized for reacting to balance changes, transitions, and run-out. They may be coalesced, delayed, or retried. Use analytics and reconciliation for closed reporting windows and the webhook event reference for exact payload fields.