Resellers & Hierarchy
ProxPanel supports a one-level deep parent / sub-reseller hierarchy with strict ownership boundaries.
What a reseller is
Section titled “What a reseller is”A reseller is a billing partner. They have their own balance, can create subscribers under their account, and optionally can create sub-resellers beneath themselves.
Key fields on resellers:
parent_id— nullable. NULL = top-level. Set = sub-reseller of that parent.balance— current credit, in your operator-defined currency.credit— how negative the balance is allowed to go.permission_group— controls what their User accounts can do (see Permissions).allowed_ips— comma-separated CIDR / single IP list. Blank = no restriction.rebrand_enabled— whether they can override the login page logo / colors.custom_domain— their white-label DNS name.
Every reseller has at least one User account (the login they use). Users have a user_type and a reseller_id pointing back to the reseller row.
Hierarchy rules
Section titled “Hierarchy rules” Admin (no reseller_id) │ ┌──────────┼──────────┐ ▼ ▼ ▼ Reseller A Reseller B Reseller C ← top-level (parent_id = NULL) │ ┌───┴───┐ ▼ ▼ Sub-A1 Sub-A2 ← parent_id = A.id- A top-level reseller sees their own subscribers + their direct sub-resellers’ subscribers (one level).
- A sub-reseller sees only their own subscribers.
- The hierarchy is one level deep. Sub-sub-resellers are not supported.
Subscriber ownership
Section titled “Subscriber ownership”Every subscriber has exactly one reseller_id. Ownership transfers are strictly gated:
| Caller is… | Can transfer to… |
|---|---|
| Admin | Any reseller |
| Top-level reseller | Themselves OR their own direct sub-resellers |
| Sub-reseller | Themselves only (no upward / sideways transfers) |
This is enforced in the Update handler and the BulkAction set_reseller case (v1.0.546 + v1.0.547). Attempts to transfer outside the allowed set are logged as SECURITY: Update refused reseller_id change.
Balance flow
Section titled “Balance flow”When a reseller renews a subscriber:
reseller.balance -= subscriber.price- Transaction row created with
type = 'renewal',amount = -subscriber.price. - Subscriber’s
expiry_dateextended.
If the balance would go below -credit, the renewal is refused.
For sub-resellers, the parent’s balance is not auto-deducted — sub-resellers manage their own balance independently. The parent grants balance via Add Money → reseller, which itself creates a transaction.
allowed_ips (IP whitelist)
Section titled “allowed_ips (IP whitelist)”Per-reseller login restriction. Comma-separated:
<subscriber-ip>,<subscriber-ip>/24,5.6.7.8Empty = no restriction.
The check fires:
- On login (refuses if source IP not in list).
- On every JWT-authenticated request (mid-session IP changes also get blocked).
Important: the source IP is the public IP seen by your nginx — what your customer’s router NATs out as, not the PPPoE internal IP. For PPPoE-tied restrictions you need to whitelist the BNG’s outbound NAT range or use a VPN / WireGuard tunnel.
In v1.0.548 the check was widened: it now applies to any non-admin user linked to a reseller, not just UserType = Reseller. So Support / Readonly / Collector staff linked to a reseller now also get IP-whitelisted.
Custom branding
Section titled “Custom branding”If rebrand_enabled = true:
- Reseller can upload their own logo (login page + customer portal).
- Override primary color.
- Set a custom domain (Reseller’s customers reach the same ProxPanel via
panel.theirdomain.com). - Customize login-page tagline + feature boxes.
The portal auto-detects which reseller the visitor belongs to (via subdomain or login) and loads their branding.
Reseller-only features
Section titled “Reseller-only features”- WAN Check — per-reseller toggle for outage detection on customer routers (ICMP + port checks).
- WhatsApp integration — per-reseller Ultramsg account for sending invoice + receipt messages.
- Notification banners — admin can broadcast to a specific reseller’s tenants.
See Custom Branding for the full set.