Every WHMCS product that uses the module runs in one of three modes, set by the Account Type config option on the product. Line creates an IPTV line on the panel; it is the default and the common case. Sub-Reseller creates a reseller account on the panel; useful when you resell reseller accounts on top of your own. Credit top-up (existing Sub-Reseller) adds credits to an existing Sub-Reseller account on that panel, instead of creating anything new; useful when your resellers buy credit packages from your website.

The three modes share the same lifecycle actions (create, suspend, unsuspend, renew, change password, terminate, change package), and every action maps to a different panel call in each mode: Credit top-up answers some of them with a deliberate refusal instead of a call. This page enumerates the exact mapping so you can predict what will happen at every step.

Every mode below starts with the create action, which runs at the moment you chose on the product: on the order being placed, on the first payment, or when you accept the order manually (see When the setup runs).

Line mode

The default and by far the most common configuration. Each WHMCS service under a Line product corresponds to one line on the panel, addressed by its numeric id.

CreateAccount

Runs when WHMCS provisions the service, at the moment you chose on the product (see the top of this page). The module runs the following steps in order:

  1. Read the product's config options: Panel, Package, Bouquets, Max Connections.
  2. Generate a username and a password with the generators configured in the addon's General Settings (or take the values WHMCS supplied on the service if you disabled auto-generation). When the product's Customer username option reads the username from the Line username custom field, that value is used instead: see Customer-chosen usernames below. When the product's Customer password option reads the password from the Panel password custom field, that value is used instead: see Customer-chosen passwords below.
  3. Render the notes template with the client's fields ({service_id}, {client_id}, {client_name}, {client_email}, {client_phonenumber}, {product_name}).
  4. If the panel entry's Key type is Admin, pick up Admin owner member_id from the panel entry.
  5. POST to /panel-api/v1/lines with a body of {package_id, member_id, username, password, bouquets[], max_connections, notes}. On a reseller key member_id is omitted and the panel infers ownership from the token. On a reseller key max_connections is also omitted; the panel would refuse it anyway.
  6. Save the returned id, username, password and expiry on the WHMCS service, so the customer sees the credentials in their client area.
  7. If the WHMCS billing cycle is not one-time or free, write the panel's expiry into the service's next due date.

The line is now live on the panel and visible to the customer in the WHMCS client area, complete with the M3U URL if you configured one on the panel entry.

Customer-chosen usernames

Module 1.9.0 and later on Line products, and module 1.10.0 and later on Sub-Reseller products too. By default the module generates the username from the addon's credential settings. A product can instead take it from a WHMCS custom field the customer fills in at checkout: set the product's Customer username option to Customer types it in the "Line username" or "Reseller username" custom field and add a custom field named Line username (also accepted: Username, Panel username), type Text Box, with Show on Order Form ticked and Required if you want to force it. The field setup and the accepted field names, per account type, are in Configure. Sub-Reseller products take the same option from a Reseller username field: see Customer-chosen credentials.

When the order provisions, the module:

  1. Reads the custom field and validates the value: 3 to 32 letters, digits, dashes or underscores.
  2. Looks the username up on the panel (GET /panel-api/v1/lines?username=…). If a line already uses it, the action stops with The username "X" is already taken on this panel. Ask the customer to choose another one. and the WHMCS order stays pending.
  3. When the username is free, sends it as username on POST /panel-api/v1/lines and takes the password from the credential settings, or from the customer's Panel password field when the Customer password option is on (see Customer-chosen passwords).

An invalid value stops the action with The username "X" is not valid: use 3 to 32 letters, digits, dashes or underscores. In both failure cases nothing is created on the panel and an operator resolves it from the WHMCS service page: correct the value and run Create again, or ask the customer for another one. A username that was free at checkout can still be taken by the time the invoice is paid.

The cart checks the same field before payment, and the module never links an existing panel line from a customer order: a customer-chosen username that matches a line already on the panel fails instead of adopting that line, so one client can never end up with another client's line, expiry or password. With the option left at Generated by the module (default), or with the custom field empty, usernames are generated exactly as before. Credit top-up products ignore the option, and it is hidden on them. The messages the cart returns are in Troubleshooting.

Customer-chosen passwords

Module 1.10.0 and later, on Line and Sub-Reseller products. A product can take the password from a WHMCS custom field the customer fills in at checkout: set the product's Customer password option to Customer types it in the "Panel password" custom field and add a custom field named Panel password (also accepted: Password, Line password, Reseller password), type Password, with Show on Order Form ticked and Required only if you want to force it. The field setup, the accepted field names and the note on where the value lives are in Configure.

When the order provisions, the module:

  1. Reads the custom field and validates the value: 8 to 32 characters, no spaces and none of % & ? # / \ + " < >.
  2. Sends it as password on the create call (POST /panel-api/v1/lines or POST /panel-api/v1/resellers) instead of generating one.

An invalid value stops the action with The password is not valid: use 8 to 32 characters without spaces and without % & ? # / \ + " < > and the WHMCS order stays pending. The cart checks the same value before payment, so most mistakes are refused before the customer pays. With the option left at Generated by the module (default), or with the custom field empty, passwords come from the addon's General Settings as before.

Once the account exists the module empties the password custom field on the WHMCS service, so the password stays only in the service's Password field, the one the customer sees in the client area. Read the short note in Configure about the window before the service is created and about the WHMCS Order Confirmation email. The module never displays the password and never writes it to the Module Log.

Linking a line that already exists

Module 1.9.0 and later. When a customer already had a line on the panel before WHMCS, a Line service can adopt that line instead of creating a second one. The button is Link existing line, in the Module Commands row of the service page, and it is only offered on Line products.

  1. Create the WHMCS service (or accept the pending order) without running the module's Create: when you accept an order, uncheck Run Module Create. Nothing is provisioned on the panel and no credits are spent.
  2. Type the username of the panel line in the service's Username field and press Save Changes.
  3. Press Link existing line.

The module reads the line from the panel by that username (GET /panel-api/v1/lines?username=…), writes the link for the service, stores the line's username and password on the service so the client area card renders its credentials, and records Linked to existing line #<id> (<username>), expires <date> as the last module action. It does not call the create, update or delete endpoints and it does not touch the WHMCS next due date: to bring the two dates together use Set WHMCS next due date to panel expiry or Set panel expiry to WHMCS next due date. From that point Renew, Sync, Refresh, Change Password and the client area work on that line exactly as on a line the module created.

The button answers with an actionable message when it cannot do the job:

  • This service is already linked to line #<id> (<username>). The service already points at a panel line.
  • Type the panel username in the Username field of this service, save, then press Link existing line. The Username field is empty.
  • No line with username "X" was found on this panel. No line on this panel uses that username.
  • Link existing line is only available for Line products. The service belongs to a Sub-Reseller or Credit top-up product.

To link many services at once, use Bulk tools → Index panel lines followed by Link existing services. See Bulk Tools.

Suspend and Unsuspend

Fires when WHMCS moves the service to Suspended (unpaid invoice, admin action, or a dunning rule) or back to Active.

  • Suspend. POST to /panel-api/v1/lines/{id}/disable. The panel flips enabled=false and the customer can no longer stream. No credits are charged, and the line is preserved on the panel with its username, password and history intact.
  • Unsuspend. POST to /panel-api/v1/lines/{id}/enable. The panel flips enabled=true and streaming resumes immediately.

From module 1.5.3 the product's Suspend action config option decides this. Disable the line on the panel is the default and the behaviour above. Leave the line untouched, let it expire makes both actions skip the panel entirely: the line keeps streaming until its own exp_date and expires on its own, and unsuspending does not enable it either (a line you disabled by hand in the panel stays disabled). WHMCS's own service status still moves to Suspended and back. Sub-Reseller products ignore the option.

Neither action changes the line's expiry date. If the line's expiry is in the past, the customer still cannot stream after Unsuspend; you need a Renew for that.

Renew

Fires when a renewal invoice is paid, or when an admin runs a manual renewal on the service.

  1. POST to /panel-api/v1/lines/{id}/renew with {package_id} set to the product's current package.
  2. The panel adds one cycle worth of duration to the line's exp_date, applies the package's connection count, clears the trial flag and returns the new line.
  3. With an admin key, if the product resolves to a connection count of its own (Max Connections or a connections configurable option) and it differs from what the panel returned, the module sends one POST /lines/{id}/update with max_connections so the renewal never drops the customer to the package's own count. That extra write is best effort: if it fails, the renewal is still reported as successful and the error goes to Module Logs, because the line is already renewed on the panel and a WHMCS retry would charge it twice (module 1.5.3 and later).
  4. The module writes the new expiry back into the service's next due date.
  5. Since 1.6.0 the module reads the line before renewing and sends an Idempotency-Key derived from the line's current expiry, the service id and the package. A double click on Renew, or a WHMCS retry of the same renewal, therefore extends the line once. The service tab records Renewed: <old expiry> -> <new expiry> and, if the line was Disabled or Blocked by panel before the call, notes that the panel enabled it again.

The module does not send bouquets on Renew. If you have changed the product's bouquet selection and want the change on the line, use the Sync bouquets, notes & connections button on the service's Admin tab (see below).

ChangePassword

Fires when the customer clicks Change Password in the client area, or when an admin resets it.

The module inspects the value WHMCS passed. If it is 8 to 32 alphanumeric characters, it is honored as-is. Otherwise the module generates a fresh password with the addon's Password Generator settings. Either way, the module POSTs to /panel-api/v1/lines/{id}/reset-password with {password} and updates the WHMCS record.

Terminate

Fires when the customer or an operator cancels the service.

POST to /panel-api/v1/lines/{id}/delete. The panel removes the line permanently. The module then unlinks the WHMCS service from the panel record so a later re-provisioning (with a fresh order) starts clean.

Terminate is permanent on the panel side. If the customer changes their mind after cancellation, you have to re-provision, which creates a brand new line with brand new credentials. The old username and password cannot be recovered.

ChangePackage (WHMCS product change)

Fires when an operator switches the WHMCS service to a different product, and also when a customer changes a configurable option on the service through Upgrade/Downgrade Options and the upgrade invoice is paid, since WHMCS routes both through the same action. What happens next depends on whether the product points at the same panel package, and on the Key type of the panel entry.

  • Same panel package_id, either key type. The module calls POST /lines/{id}/update with the new bouquets, notes and (admin key only) max_connections, resolved from the product's Max Connections and any connections configurable option (see Configure). The line keeps its id, its username, its password, its history and its expiry; only the configuration changes.
  • Different panel package_id, admin key. The module calls POST /lines/{id}/update once, sending package_id, the new product's bouquets, the notes and, when the product sets a non-zero Max Connections or carries a connections configurable option, the resolved connection count. The panel applies the new package to the line in place. The line keeps its id, its username, its password, its history and its expiry, and no credits are spent. The module then records the new package id against the WHMCS service, so both sides agree from that moment on. This is a plain upgrade or downgrade: bill the difference in WHMCS, because the panel charges nothing for the swap.
  • Different panel package_id, reseller key. The module refuses before it calls the panel, with Changing the panel package requires an admin panel key. With a reseller key, terminate and re-provision the service. There is no workaround: the panel rejects package_id on the update endpoint for a reseller key with 403 admin_only_field, because a reseller moving a line onto a richer package for free would be a way around the credits a renewal charges. The WHMCS service stays linked to the old panel line and nothing on the panel changes; with a reseller key the routes to another package are a renewal, which charges a full period, or a terminate and re-provision, which issues new credentials.

Package changes need a panel updated on or after 2026-09-14. On an older panel package_id is an unknown field: the update call is accepted and the field is ignored, so the package change is not applied even though WHMCS records the new product. The two sides then disagree silently. If you are not sure which build your panel runs, ask your panel operator before you rely on product changes.

Whichever branch runs, the expiry does not move. A product change is not a renewal: if the customer is also paying for another cycle, WHMCS raises that invoice and the renewal handles it separately.

Two things to get right on the new product before you run a product change, both of them config options you already fill in for every product:

  • Bouquets must belong to the new package. The module sends the new product's bouquet selection along with the package, and the panel accepts only bouquets that are part of the package you are moving to. If any of them is not, the panel rejects the whole call, names the offending ids, and nothing changes on either side: the line keeps its old package and WHMCS keeps the old service record. Pick the bouquets for the new product from the package you are moving to and the change goes through in one shot.
  • Connections resolve the same way they do on CreateAccount. The product's Max Connections is an absolute value: set 5 and the line ends up on 5. An extra_connections configurable option is added on top of it, or on top of the new package's own count when Max Connections is 0. With neither, the line takes the new package's connection count.

The restreamer flag is not a product option: it follows the new package, so a line moved onto a restreamer package becomes a restreamer and a line moved off one stops being one.

Sync bouquets, notes & connections

Not a WHMCS lifecycle action. A custom admin button on the service page (called Sync line to panel before 1.6.0) that runs the same call ChangePackage runs in the same-package branch: POST /lines/{id}/update with the current bouquets, notes and the resolved connection count (Max Connections plus any connections configurable option on the service). Use it when you edit the product's config options without changing the product, or when you want a quick way to force the panel line to match the WHMCS product without waiting for the next renewal.

Sync does not send package_id, does not change the line's enabled state and does not touch the expiry. If you change the Package config option on a product that already has live services, the button pushes the new bouquets, notes and connection count but leaves each line on its original package. To move a line onto another package, run a product change from the service page with an admin key. To move the expiry, renew the service or use the expiry buttons described below.

Since 1.6.0 the module stores the status and expiry the panel returns from that call, so the service tab is current right after the sync, and any field the panel ignored (for example an admin-only field sent with a reseller key) is shown as a warning in the tab instead of being dropped silently.

Sub-Reseller products do not expose this button.

The service tab and the expiry buttons

Since 1.6.0 the module's tab on the WHMCS service page reads the line from the panel when you open it (cached for 90 seconds per service, with a 5 second timeout so a slow panel never blocks the page) and shows:

Field Meaning
Panel, Panel line ID, Panel username Which panel entry and which line the service is linked to.
Line status Active, Expired, Disabled (the line's enabled flag is off) or Blocked by panel (the panel administrator blocked it).
Active connections Live count from the panel.
Panel expiry The line's expiry as the panel has it.
WHMCS next due date The service's next due date in WHMCS, shown next to the panel expiry so a mismatch is obvious.
Panel checked When the panel was last read and whether the row is live or cached. If the read failed, the reason and the age of the data shown.
Last module action What the last command did, for example Renewed: 16/09/2026 -> 16/09/2027 (package #17).
Warning Shown only when needed: a date mismatch of more than one day, or fields the panel ignored on the last update.

Five buttons sit in the Module Commands row for Line products:

  • Sync bouquets, notes & connections (above).
  • Refresh from panel: forces a new read, ignoring the 90 second cache.
  • Link existing line: links the service to a line that already exists on the panel, using the username typed in the service's Username field (see above).
  • Set panel expiry to WHMCS next due date: writes the WHMCS date to the line's expiry (at 12:00 UTC of that day). Requires an admin panel key; with a reseller key the module refuses before calling the panel.
  • Set WHMCS next due date to panel expiry: copies the line's expiry into the service's next due date. Not available on One Time or Free billing cycles.

Editing the next due date by hand in WHMCS never changes the panel, and suspending or unsuspending a service in WHMCS changes the line's enabled flag but not its expiry. When the two dates drift apart the tab says so and these two buttons put them back in line. To push the WHMCS date to every linked line of a panel in one run, use the Align panel expiry to WHMCS card in Bulk Tools (module 1.7.0 and newer).

What the customer sees

For a Line product the client area card shows the username and the password (each with a Copy button, the password behind a Show/Hide toggle), the line status as the panel reports it, the expiry date, the M3U URL if the panel entry carries one, and the Active Connections table with the current stream, IP, country and elapsed time, read live from the panel. From module 1.14.0 the Active Connections counter also shows the maximum the line allows, such as 1 / 2. The full description of the card is in the Overview. If the line has not been created yet (for example, the invoice was just paid), the card shows a "Your IPTV line is not ready yet" notice and no fields.

Sub-Reseller mode

Set Account Type to Sub-Reseller on a product to have every order create a reseller account on the panel instead of a line. This mode is only usable with an admin key. See Reseller vs Admin Keys for the full rationale.

CreateAccount

Runs when WHMCS provisions the service, at the same moment as in Line mode.

  1. Read the product's config options: Panel, Credits, Sub-Reseller Member Group. The Package and Bouquets options are ignored in this mode.
  2. Verify the WHMCS client has an email address. Sub-reseller accounts require one; the module refuses to proceed with A client email address is required to provision a Sub-Reseller account. if the field is empty.
  3. Generate a username and a password with the addon's generators. A product can take either or both values from a custom field the customer fills in at checkout: see Customer-chosen credentials below.
  4. POST to /panel-api/v1/resellers with {username, password, email, credits, notes, member_group_id}. The credits field is only sent when non-zero; the member_group_id field is required and comes from the product's Sub-Reseller Member Group option.
  5. Save the returned id, username and credit balance on the WHMCS service, so the customer sees the credentials in their client area.

The new reseller account is now visible in the addon's Sub-Resellers tab, with its username, email, member group and credit balance.

If the Sub-Reseller Member Group option is missing or set to a group id that does not exist on the panel, the create call returns The panel rejected the request values. and the service stays in a pending state. Fix the group id on the product's Module Settings tab and re-run the CreateAccount from the service page.

Customer-chosen credentials

Module 1.10.0 and later. A Sub-Reseller product can take the username and the password from custom fields the customer fills in at checkout, with the Customer username and Customer password options. This is the behaviour Line products have had since 1.9.0, extended to Sub-Reseller products in 1.10.0. Both options show with Account Type Line and Sub-Reseller and are hidden on Credit top-up products.

  • Username. Set Customer username to Customer types it in the "Line username" or "Reseller username" custom field and add a custom field named Reseller username (also accepted: Sub-Reseller username, Panel username, Username). The module validates it (3 to 32 letters, digits, dashes or underscores) and checks the panel both when the cart takes the order and again when the service is created. The lookup against the panel runs only when the panel entry's Key type is Admin: the cart then stops a taken name with The reseller username "X" is already taken. Choose another one. and the create step stops it with The reseller username "X" is already taken on this panel. Ask the customer to choose another one., leaving the order pending. With a Reseller key the module does not look the name up: the cart accepts it, and the panel refuses a duplicate when the account is created, so the order stays pending with the panel's own message. A value that does not fit the format answers The username "X" is not valid: use 3 to 32 letters, digits, dashes or underscores. A panel that does not answer never blocks the cart, because the name is checked again when the service is created, exactly as on Line products.
  • Password. Set Customer password to Customer types it in the "Panel password" custom field and add a custom field named Panel password (also accepted: Password, Line password, Reseller password), type Password, with Show on Order Form ticked. The module accepts 8 to 32 characters, no spaces and none of % & ? # / \ + " < >, and refuses anything else in the cart and at creation with The password is not valid: use 8 to 32 characters without spaces and without % & ? # / \ + " < >.

Once the account exists the module empties the password custom field on the WHMCS service and the password stays only in the service's Password field, where the customer sees it in the client area; the note in Configure covers the window before that and the Order Confirmation email. Field names, WHMCS field types and the full list of checks are in Letting the customer choose the username and Letting the customer choose the password. The messages are collected in Troubleshooting.

Suspend, Unsuspend and Terminate

Fires when WHMCS moves the service to Suspended or Terminated, or back to Active.

The panel API does not currently expose a reseller status field: the reseller update endpoint accepts fields like username, email, member group, notes and password, but no switch to enable or disable the account. So when one of these three actions fires on a Sub-Reseller product, the module attempts the change, re-reads the account, sees that its status did not change, and raises The panel API does not support changing a reseller status. Please disable this account manually from the panel and try again. The link between the WHMCS service and the account is preserved, so the action is safe to retry once the account is in the state you want.

To disable a sub-reseller today, log in to your panel, find the reseller under Users, and disable them there. The WHMCS service keeps tracking the same account and picks up the state correctly on the next reconciliation.

When the panel gains an official reseller status endpoint, the module will start honoring Suspend, Unsuspend and Terminate automatically. No configuration change on your side will be needed.

Renew

Fires when a renewal invoice is paid.

If the product's Credits option is greater than zero, the module POSTs to /panel-api/v1/resellers/{id}/billing/adjust with {delta: <credits>, reason: "WHMCS renewal service #<id>"}. The panel adds the delta to the reseller's balance and returns the new balance.

If the product's Credits option is zero, the renewal is a no-op on the panel side (nothing to add) and the module simply updates the WHMCS service status to Active.

Adding or removing credits by hand

Renewal is not the only way to move credits. In Addons → Xtream AI Panel → Sub-Resellers, select the panel and every account created through the module is listed with its username, email, member group, status and balance. The last column of each row is a small form: type the amount in the number field (positive to add, negative to remove, for example 50 or -20), optionally a reason, and press Apply. The module POSTs to /panel-api/v1/resellers/{id}/billing/adjust with that delta and shows the new balance the panel returned.

With an admin key the form adjusts that account. With a reseller key (module 1.13.0 and later, key with subresellers:read and subresellers:credits) the tab lists that reseller's own sub-resellers and the form transfers: a positive amount leaves the reseller's own balance, a negative amount takes credits back from a direct sub-reseller if the panel allows it. Amounts are limited to ±100000 per adjustment, and the reason, when given, is stored on the panel next to the movement so it shows up in the reseller's credit history.

ChangePassword

Fires when the customer clicks Change Password, or when an admin resets it.

The password validation and generation logic is identical to Line mode: honor a WHMCS-supplied 8-to-32 alphanumeric password, generate one otherwise. The module then POSTs to /panel-api/v1/resellers/{id}/update with {password} and updates the WHMCS record.

ChangePackage

Not supported for Sub-Reseller products. The module refuses with Package changes are not supported for Sub-Reseller products. because packages are a Line concept and do not apply to reseller accounts.

What the customer sees

For a Sub-Reseller product, the client area card shows:

  • Username and Copy button.
  • Password with Show/Hide and Copy.
  • Status (Active or Suspended, driven by WHMCS).
  • Credit balance (only shown for Sub-Reseller products).
  • Login instructions pointing at the panel's reseller area if you configured them in the addon settings.

The Active Connections table and the M3U URL are not shown for Sub-Reseller products; both are Line-only concepts.

Credit top-up mode

Set Account Type to Credit top-up (existing Sub-Reseller) on a product to sell credits rather than access. When the service is paid (CreateAccount) or renewed (Renew), the module adds the configured amount to an existing Sub-Reseller account on that panel, instead of creating a new account. Nothing new appears under Users on the panel: the balance of an existing account goes up, and the movement is recorded in that reseller's credit history.

This mode is only usable with an admin key on the panel entry, for the same reason Sub-Reseller products are: the panel issues the resellers:* scopes to admin keys only. See Reseller vs Admin Keys.

Choosing the amount

The amount added on each CreateAccount and Renew is resolved in this order:

  1. A WHMCS Configurable Option on the product named credits (also accepted: credit_amount, topup_credits). The name is compared case-insensitively and anything after a | is ignored, so credits|Credit package displays as "Credit package" and still matches.
  2. The product's Credits value on the Module Settings tab, used when the product has no such configurable option.

That is what lets one top-up product sell 100, 500 and 1000 credit packages at different prices: the configurable option carries the amount the customer picked, and the product's Credits field is the fallback.

If the resolved amount is zero, the module refuses before calling the panel: No credit amount configured for this top-up product. Set Credits on the product's Module Settings tab or add a configurable option named credits.

Choosing the account

The destination is not picked by hand. The module resolves it in this order:

  1. A linked Sub-Reseller service of the same client. The module looks at the WHMCS client's own services and keeps the ones that are Sub-Reseller products, Active in WHMCS, already linked to an account on the panel, and pointed at the same panel as the top-up product. Services created through the module are linked from the start; services that existed before it are linked once with Bulk tools → Link. Without a custom field on the product this list is the only source, and then:
    • Exactly one service. The credits go to the account that service is linked to.
    • None. The module stops with This client has no active Sub-Reseller service on this panel to top up. Add a required custom field named "Reseller username" to the top-up product so the customer types the panel account, or order the Sub-Reseller product first. The order stays pending in WHMCS; once the client has a linked Sub-Reseller service on this panel, run Create again from the service page.
    • More than one. The module stops with This client has several Sub-Reseller accounts on this panel (a, b). Add a required custom field named "Reseller username" to the top-up product so the customer chooses the account. The message lists the usernames it found.
  2. The username the customer typed, looked up on the panel. Add a WHMCS Custom Field to the top-up product (Products/Services → your product → Custom Fields) named Reseller username (also accepted: Panel username, Sub-Reseller username), ticked Required and Show on Order Form. If the value matches a linked Sub-Reseller service of that client on this panel, that service is the destination. If it does not, the module looks the username up directly on the panel (GET /panel-api/v1/resellers?username=…, admin key) and credits the account it finds there, even when an admin created that account by hand and it never went through WHMCS. The username comparison ignores upper and lower case, but the account has to exist on the panel with the username as it was created there. The top-up service is then linked to that account, so its renewals keep crediting it. The panel lookup runs only when the product's Top-up scope option is Any reseller on the panel, the default and what every product saved before 1.8.2 reads. With Top-up scope set to Only this client's linked Sub-Reseller accounts, the module stops at the linked-service match: a username that is not one of the client's Sub-Reseller services linked on this panel is refused before any panel call, with The reseller username "<value>" does not match any of this client's linked Sub-Reseller accounts on this panel.
  3. Nowhere. If the username exists neither as one of the client's linked services nor on the panel, the module refuses with The reseller username "<value>" was not found on this panel.

Whichever step resolves the destination, a username that belongs to a panel administrator is refused before any credit moves, with The reseller username "<value>" belongs to a panel administrator and cannot receive a top-up. That covers an account in the panel's administrator group and the account set as Admin owner member_id on the panel entry: administrator accounts hold no reseller credit balance to top up.

Module 1.9.1 and later checks the same value in the cart before payment, and the module resolves the destination again when it creates the service. With Any reseller on the panel the cart asks the panel about the username; with Only this client's linked Sub-Reseller accounts it compares the value against the linked accounts of the signed-in client, so a customer who is not signed in is not checked in the cart at all and only meets the refusal when the service is created. The messages this produces, and what to do about each one, are in Troubleshooting; the scope itself is described in the Top-up scope row of Configure.

With the custom field on the product, any client who buys the top-up can type the username of any reseller on the panel. The credits are paid for, so the worst outcome is that a client gifts credits to another account; nobody can take credits away. If you do not want that, set the product's Top-up scope option to Only this client's linked Sub-Reseller accounts, which accepts only usernames that match a Sub-Reseller service of the same client linked on that panel.

A top-up service never creates an account. If neither the client's linked Sub-Reseller services nor the panel lookup resolve a destination, there is nobody to credit and the module stops with the message above. Order the Sub-Reseller product for the client, or check the username against the panel under Users.

CreateAccount

Runs when WHMCS provisions the service, at the same moment as in Line mode.

  1. Resolve the amount as described in Choosing the amount above, and the destination account as described in Choosing the account above.
  2. POST to /panel-api/v1/resellers/{id}/billing/adjust with {delta: <credits>, reason: "WHMCS top-up service #<id>"}, where <id> is the WHMCS service id.
  3. The panel adds the delta to the reseller's balance and returns the new balance. The movement, with its reason, is stored next to the account and appears in the reseller's credit history.
  4. The WHMCS service is linked to the destination account, so the username is visible on the service, and the action is recorded in Last module action: Topped up +50 credits to <username> (balance 150).

Pressing Create again on a service whose credits were already added does not credit it twice: the module refuses with This top-up was already applied (…). Use a renewal or the Sub-Resellers tab to add more credits. More credits are added with a renewal or by hand from the Sub-Resellers tab.

Renew

Fires when a renewal invoice is paid.

The amount is resolved again the same way and added to the same account the service is linked to, with reason: "WHMCS top-up renewal service #<id>". On a recurring billing cycle this makes the service a subscription, for example "100 credits per month". On a One Time cycle there is no renewal, so the product is a single purchase.

Suspend, Unsuspend and Terminate

These actions only change the state of the WHMCS service:

  • Suspend and Unsuspend do not touch the panel. The credits belong to the Sub-Reseller account, not to the top-up service, so a suspension never takes them away.
  • Terminate unlinks the WHMCS service from the destination account. The reseller account and its credits stay exactly as they are.

Because no lifecycle action ever reverses a top-up, the credits stay on the reseller account after the top-up service is cancelled. Adjust them by hand from the Sub-Resellers tab if you need them gone.

What is not supported

  • Change Password. The module refuses with Password changes are not supported for Credit top-up products: the password belongs to the Sub-Reseller service.
  • Change Package. The module refuses with Package changes are not supported for Credit top-up products.
  • Sync, Refresh and the expiry buttons. A top-up service has no line of its own, so those commands are not offered: the buttons do not appear in the service tab.
  • Bulk tools. The Link, Sync and Align expiry operations skip top-up services and count them as Credit top-up skipped.

The service tab

The module's tab on a top-up service shows the destination account as username (id …), how many credits each order adds (resolved from the configurable option or the product's Credits), the account's credit balance read live from the panel, and the last module action, for example Topped up +50 credits to <username> (balance 150).

Before the top-up has been applied, the tab says Not applied yet. The top-up runs when the service is created.

What the customer sees

For a Credit top-up service the client area renders a card titled Credit Top-Up with:

  • The Sub-Reseller account, as the username plus a Copy button.
  • Credits per order.
  • Current balance.
  • Status.

There is no password and no M3U or EPG URL on this card: the access belongs to the Sub-Reseller account, not to the top-up.

For the common case of resellers buying credits from your website, two products are enough:

  1. A Sub-Reseller product that creates the account, with the credits it starts with.
  2. A Credit top-up product with the Reseller username custom field and a configurable option named credits (a Quantity, or a Dropdown with 100 / 500 / 1000), on a One Time cycle, or a monthly cycle if you want an automatic recharge every month.

Leave Top-up scope at its default, Any reseller on the panel, when your top-up customers are resellers who may never have gone through WHMCS: with the custom field in place, any reseller on the panel can buy credits by typing their username, whether or not WHMCS ever created their account, and the module credits the account it finds on the panel under that name. Switch it to Only this client's linked Sub-Reseller accounts when a top-up must always land on an account the ordering client owns in WHMCS.

See also

  • Configure. How to pick the Account Type and set the config options each mode needs.
  • Reseller vs Admin Keys. Why Sub-Reseller products require an admin key and which lifecycle actions are unreachable on the panel API today.
  • Troubleshooting. Common failures for each mode and how to resolve them.