Skip to content

Resellers & Hierarchy

ProxPanel supports a one-level deep parent / sub-reseller hierarchy with strict ownership boundaries.

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.

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.

Every subscriber has exactly one reseller_id. Ownership transfers are strictly gated:

Caller is…Can transfer to…
AdminAny reseller
Top-level resellerThemselves OR their own direct sub-resellers
Sub-resellerThemselves 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.

When a reseller renews a subscriber:

  1. reseller.balance -= subscriber.price
  2. Transaction row created with type = 'renewal', amount = -subscriber.price.
  3. Subscriber’s expiry_date extended.

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.

Per-reseller login restriction. Comma-separated:

<subscriber-ip>,<subscriber-ip>/24,5.6.7.8

Empty = 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.

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.

  • 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.