WHMCS module
Resell Swarmz from WHMCS with no code. Install the module, set your API key once, create a server, and every WHMCS service lifecycle event provisions, signs in, suspends, and tears down a tenant for you.
If you already run WHMCS, this is the fastest way to resell Swarmz. WHMCS keeps the billing and the customer relationship; the module turns each service lifecycle event — create, suspend, terminate — into a single call to the Platform API. You write no code.
Setting up for the first time?
Follow the WHMCS setup walkthrough — every step in order, from an empty WHMCS to selling plans and credit packs, in about 30 minutes. This page is the full reference behind it.
Open source, MIT licensed
The module lives at github.com/swarmzlabs/whmcs-module. Download the latest release to install. Read the source, open issues, or fork it.
What you get
The download installs two modules in one step.
Provisioning module
A WHMCS server module. Attach it to a product and WHMCS drives the full tenant lifecycle — create, plan change, suspend, unsuspend, terminate — through the Platform API.
Reseller Console
An admin addon where you set your API key once and see every customer's plan and live credit + cloud usage (your wholesale cost) in one place — plus the embeddable Prompt Box for your storefront.
Requirements
Everything the module needs, on one board. If your WHMCS runs, you almost certainly meet all of it — the only line hosts ever actually trip on is file ownership for the auto-updater.
| Requirement | Minimum | Used for |
|---|---|---|
| WHMCS | 8.x or newer | Module APIs, hooks, client-area templates |
| PHP | 8.1 or newer | The module is modern, plain PHP — no encoders |
curl extension | enabled | Every Swarmz API call, and downloading updates |
json extension | enabled (bundled with PHP 8) | API request and response bodies |
mbstring extension | enabled | Safe text handling — prompts, release notes, translations |
zip extension (ZipArchive) | enabled — auto-updater only | Extracting the release ZIP in Console → Updates. Without it the module still runs fine; you just update by ZIP upload instead |
| Outbound HTTPS (port 443) | to api.swarmz.net | All platform calls. On a private endpoint? Allow that host instead |
| Outbound HTTPS for updates | to api.github.com, github.com, *.githubusercontent.com | The auto-updater's release check and download (release assets redirect to githubusercontent.com) |
| File ownership | module folders owned by the PHP user — dirs 755, files 644 | The one-click auto-updater. Set it once: File permissions |
| Swarmz account | active, with your sk_live_… key | A draft account returns 409 account_inactive — contact us to activate. See Authentication |
Explicitly NOT needed — nothing to install or configure for any of these:
- ionCube Loader — the module is open-source, plain PHP; nothing is encoded. (Your WHMCS core ships with ionCube anyway — the module simply doesn't use it.)
- A cron job of its own — it rides the standard WHMCS automation you already run (why).
- Composer, Node, or shell access — the release ZIP is complete; unzip and go.
allow_url_fopen— all HTTP goes throughcurl.- Database changes — the module creates its own two small
mod_swarmz_*tables through WHMCS's normal database connection; your schema is never altered, and updates never touch your data. - Extra hash/crypto extensions — update integrity uses PHP's built-in SHA-256, which is always available.
The Updates page doubles as a requirements check
Reseller Console → Updates runs a preflight before every install: it
verifies the zip extension is present, GitHub is reachable, and the module
folders are writable by PHP — and tells you exactly what to fix when
something fails.
The key is server-to-server only
An sk_live_ key has full control of your platform account. WHMCS stores it
encrypted. Keep it on the server; never put it in client-side code or commit
it anywhere.
Install and connect
The whole setup is: drop in the files, set your key once, create one server, then point a product at it. Selling credit packs adds one addon + one mapping — see Credit packs.
Upload the module
Download the ZIP from the latest release and unzip it over your WHMCS root. It writes two folders, each where WHMCS expects:
<whmcs-root>/modules/servers/swarmz/ ← provisioning module
<whmcs-root>/modules/addons/swarmz/ ← Reseller ConsoleNothing outside those two folders is touched. While you're here, set the file ownership on both folders (PHP user, dirs 755, files 644) — one minute now, and every future update becomes a single click in the console instead of another ZIP upload.
Activate the Reseller Console and set your key
In WHMCS admin, go to Setup → Addon Modules, find Swarmz Reseller Console, and click Activate. Open its settings and paste your sk_live_… key into API Key. Leave API Base URL as https://api.swarmz.net.
Set the key here once
The server module automatically reuses this key whenever a server's Password field is left blank — so this is the only place you need to enter it. The console also uses it to show per-customer usage.
Add a server
Go to Setup → Products/Services → Servers → Add New Server.
| Field | Value |
|---|---|
| Name | Swarmz (anything you like) |
| Hostname | api.swarmz.net |
| Module | Swarmz |
| Username | leave blank |
| Password | leave blank — reuses the key from the console above |
| Secure (SSL) | on |
Save, then click Test Connection. A green result confirms your key is valid and the API is reachable.
Prefer a per-server key?
You can instead paste the sk_live_… key into this server's Password
field. If set, the server's own key wins over the console key. Either way
works; pick one.
Put the server in a group
Still under Servers, click Create New Group, name it (e.g. Swarmz), add the server you just made to the group, and save. Products attach to a group, not a server directly.
Create a product
Go to Setup → Products/Services → Products/Services and create a product (any type that supports a module, e.g. Other). On the Module Settings tab:
- Module Name: Swarmz
- Server Group: the group you just created
- Plan: pick one of your Swarmz plans from the dropdown
That single Plan dropdown is the only product option — it's populated live from the plans you build in your Swarmz dashboard (Platform → Settings → Plans). You must select a plan; provisioning fails with a clear error if you don't. See Plan selection below.
Place a test order
Create an order for the product against a test client and accept it. WHMCS calls platform-create and the module stores the new tenant's id and dashboard URL on two service custom fields it creates automatically: Swarmz Tenant ID and Swarmz Dashboard URL. The client area now shows an Open AI Editor button.
What each WHMCS action does
Once the product is live, WHMCS lifecycle events map straight onto Platform API calls. You never invoke these yourself — WHMCS does, on what your customers trigger through billing.
| WHMCS event | Calls | Effect |
|---|---|---|
| Accept order / Create | platform-create | Provisions the tenant on the selected plan (plan_code); stores its id + dashboard URL |
| Upgrade / Downgrade (Change Package) | platform-plan | Re-assigns the new plan by plan_code; the platform prorates the switch server-side |
Renewal invoice paid (InvoicePaid) | platform-plan-refresh | Rolls the credit cycle at the billing boundary — resets monthly credits, applies rollover |
Credit-pack addon invoice paid (InvoicePaid, module ≥ 1.11.0) | platform-topup | Adds the mapped pack's credits to the customer's workspace — once per paid invoice |
| Suspend | platform-suspend | Pauses compute + cloud, unpublishes sites, blocks SSO |
| Unsuspend | platform-unsuspend | Resumes compute + cloud, republishes sites |
| Terminate | platform-terminate | Permanent teardown |
| Client clicks Open AI Editor | platform-sso | Mints a fresh redirect and logs the customer in |
| Client area / Console usage | platform-usage | Reads current-period credit + cloud usage |
The module addresses each tenant by external_ref, set to whmcs:<serviceid> automatically, so you never track tenant UUIDs by hand.
Plan selection
The module ships one product option: the Plan dropdown. A product provisions purely from the named Swarmz plan you select — there are no per-option entitlement fields in WHMCS.
You build the plans themselves in your Swarmz dashboard (Platform → Settings → Plans): the credits a customer gets each cycle (Build / Cloud / AI lanes), a daily free allowance, rollover, and project / domain / compute limits. Each plan has a stable code, and WHMCS sends only that plan_code on platform-create and platform-plan — the platform resolves the full entitlement set server-side. See Platform plans for the plan model.
Every Swarmz product must have a plan selected.
CreateAccountandChangePackagefail with "select a Swarmz plan on the product's Module Settings tab" until you pick one — re-save any product migrated from an older module version (the old positional entitlement options and the initial-top-up option were removed in module v1.5.0).
Self-serve plan upgrades
Upgrades need no extra module wiring — they ride WHMCS's native product Upgrade/Downgrade flow. What's usually missing is the WHMCS-side configuration, so customers see no upgrade path at all. Set it up once:
Open the upgrade paths
For each Swarmz product, go to Setup → Products/Services → your product → Upgrades tab and tick every product the customer may move to (typically the tiers above it; tick lower tiers too if you allow downgrades). Products must be in the same currency; keep all your Swarmz tiers in one product group so they appear together.
Check your proration setting
On the same tab, WHMCS's Upgrade/Downgrade pricing applies — by default the customer pays a prorated difference for the remainder of the current cycle, and the service's recurring price changes from the next renewal.
That's the whole setup
The customer now has Upgrade/Downgrade Options on the service in their client area. When they pay the prorated upgrade invoice, WHMCS fires ChangePackage, the module sends the new plan_code to platform-plan, and the platform prorates server-side to match what the customer just paid: an upgrade immediately grants the credit difference between the plans scaled to the time left in the cycle (and meters you wholesale for exactly that prorated amount); a downgrade applies the new caps immediately and takes full effect at the next renewal, with no clawback — mirroring WHMCS's own no-refund default.
Why this matters: without the Upgrades tab configured, a customer who outgrows their plan has no path but a support ticket. Combined with credit packs below, a customer on your highest plan still has a way to buy more instead of stalling mid-build.
Credit packs — sell top-up credits
Sell extra credits as ordinary WHMCS Product Addons — the "I ran out mid-build" escape valve, and a revenue line of its own. No provisioning module on the addon; payment is the trigger.
Since module v1.19.0 your Swarmz pack catalog is the source of truth: you define packs once in the dashboard's plan builder, and WHMCS addons simply point at them. Sales are counted per pack right where you defined it.
Define the pack on Swarmz
In your Swarmz dashboard → Settings → Plans → Credit packs, add a pack: a name, the credits it grants, your reference price, and whether it's one-time (a single boost) or monthly (a standing extra allowance). Each pack gets a stable code, and its row shows a live Sold count as customers buy it through WHMCS.
One click: Create addon
Open the Reseller Console → Credit Packs (toolbar). Since module v1.20.0 this page is your pack catalog: one row per Swarmz pack, showing whether — and as which Product Addon — it is sold in WHMCS.
For a pack that isn't in WHMCS yet, click Create addon. The module creates the Product Addon as a hidden draft: billing cycle taken from the pack (one-time / recurring; a free pack becomes a Free-cycle addon), assigned to your Swarmz products, kept off the initial order form, price prefilled from the catalog — and already linked. An addon that already carries the pack's name is adopted (linked), never duplicated; the link existing picker covers any other addon.
Finish the draft in WHMCS
Setup → Products/Services → Product Addons: open the new addon, check the retail price is what you want to charge, adjust product assignment if needed, and untick Hidden — that checkbox is what lets existing customers buy it from the client-area addon store (cart.php?gid=addons), so nothing can sell until you flip it. Optionally tick Show on Order Form to offer the pack during initial checkout too. Leave Module empty — the grant rides the invoice, not addon provisioning.
The pack decides how many credits are granted, and the amount stays in sync with your catalog automatically (re-checked daily and whenever you open the Credit Packs page) — edit the pack on Swarmz and WHMCS follows. Prefer a fixed number that isn't in your catalog? The page's Custom amounts table (and the advanced by-addon view) still lets you hand-type one. A pack you archive on Swarmz never silently unmaps — it keeps granting its last known amount and is labeled truthfully until you unlink it.
Done — payment grants automatically
When a customer pays an invoice containing a mapped addon (first order or renewal alike), the module posts platform-topup and the credits land on their workspace within seconds. The client-area overview also gains a quiet "Buy more" button whenever the service's product has at least one mapped pack that isn't Hidden — it opens a designed popup listing only your packs.
Free packs grant on activation (module ≥ 1.11.1)
A Free-cycle addon never produces an invoice, so the payment trigger can't fire for it. Invoice-less packs (free cycle, or added by hand by an admin) grant once, when the addon is activated — still idempotent, still metered wholesale. Priced packs are unchanged: payment is their only trigger.
Checkout flow — how the Order button checks out
Since module v1.18.0, Reseller Console → Appearance → Checkout flow decides what happens when a customer picks a pack in the panel's popup:
- Direct to invoice (default, recommended) — the module places the addon order against the customer's service and sends them straight to the invoice to pay. A
$0pack is accepted automatically and the customer returns to the panel with a translated confirmation. Works identically with every order-form theme. - Standard WHMCS cart — the classic
cart.php?a=add&aid=…deep link, for stock WHMCS order forms. - Lagom Smart Order Form — sends the customer to Lagom's addon store page to check out inside Lagom's flow. (Lagom offers no per-addon deep link, so the customer picks the pack again there.)
Mechanics worth knowing
- Once per paid invoice. The grant is keyed
whmcs-inv<invoiceid>-ha<addonid>and the platform dedupes on it — a re-firedInvoicePaidhook, the daily sweep, and provisioning catch-up can never double-grant (or double-bill you). - Counted per pack. Every grant reports which catalog pack it sold as, so the Sold column in your Swarmz dashboard's Credit packs table stays current — no spreadsheet reconciliation.
- Self-healing. If the pack was ordered with the product, its invoice is usually paid before the workspace exists — the module grants it automatically right after provisioning, and a daily cron sweep re-checks the last 30 days of paid invoices for anything missed (API blips included).
- Wholesale billing. You are metered for top-up credits when they are assigned (charge-on-assign), same as the API — see Top up credits. Price your packs above your wholesale rate.
- They expire. Top-up credits are spendable for 12 months after purchase, and they are additive — they never touch the plan's monthly grant, rollover, or free allowance.
- Refunds are yours to police. WHMCS refunding an invoice does not claw credits back (credits may already be spent). Handle refund policy commercially — e.g. refuse refunds on consumed packs.
Automation — do you need a cron?
No. The module never needs a cron entry of its own — it rides the standard WHMCS automation every working install already runs (the system cron invoking crons/cron.php). If Utilities → Automation Status is green, everything below is already firing.
Two hooks do all the work:
Instant: InvoicePaid
Fires the moment an invoice is paid, so the event-driven paths land in seconds:
- Renewals — a paid invoice containing a Swarmz service line marks a billing-cycle boundary. The module calls
platform-plan-refreshanchored at the service's next due date: monthly credits reset and rollover applies exactly on the boundary you bill on. Idempotent per (tenant, cycle anchor) — a re-fired hook is a safe no-op. - Credit packs — every mapped addon line on the paid invoice is granted via
platform-topup, deduped onwhmcs-inv<invoiceid>-ha<addonid>.
Daily: DailyCronJob
One reconciliation pass per day, inside WHMCS's daily automation run:
- Usage refresh — a single account-wide
platform-usagecall, cached onto every service, so the client area shows live credit / cloud numbers instantly. - Status reconcile — a workspace terminated on the Swarmz side suspends the matching WHMCS service (suspend, not terminate — a human reviews before anything irreversible). Ambiguous signals are deliberately left alone so the cron can never wrongly suspend a paying customer.
- Renewal safety net — an idempotent plan refresh for every active service, anchored strictly at its next due date. If the paid-invoice moment was missed (API blip, cron outage), this heals it the next day — logged as
RenewalRecovered; a normal day is a silent no-op, and a cycle can never roll early. - Pack catalog re-sync (module ≥ 1.19.0) — pack-linked mappings re-cache their credit amounts from your Swarmz catalog, so a pack you edit on Swarmz propagates to WHMCS within a day (or instantly, whenever you open the Credit Packs page).
- Credit-pack sweep — re-checks the last 30 days of paid invoices for mapped packs. The idempotency key makes anything already granted a pure no-op; only genuinely missed grants (including packs paid before the workspace existed) are applied.
Meter Cron Secret in the console settings is optional and almost never needed — the platform schedules its own metering. Leave it blank unless Swarmz support hands you a secret.
Every run writes to Utilities → Logs → Module Log (key redacted). To force the daily pass while testing instead of waiting for the automation window:
php -q crons/cron.php all --forceTest the money paths
A 15-minute end-to-end pass against a test client, in the order the money flows:
| # | Do | Expect |
|---|---|---|
| 1 | Order the product, pay/accept | Service Active; custom fields Swarmz Tenant ID + Dashboard URL filled; Open AI Editor signs the client in |
| 2 | Order a mapped credit pack with the product | Credits appear on the workspace right after provisioning (CreditPack.Granted in the Module Log); balance visible in the client area |
| 3 | Buy a pack standalone, pay the invoice | Credits land within seconds of payment |
| 4 | Pay the same invoice again (Mark Unpaid → Add Payment) | No second grant — the log shows the call, the balance doesn't move |
| 5 | Client-area Upgrade to a higher product, pay the prorated invoice | ChangePackage in the log; workspace immediately gains the prorated credit difference; your wholesale meter shows exactly that amount |
| 6 | Downgrade back | New caps apply immediately, nothing clawed back, no wholesale charge; full effect at next renewal |
| 7 | Admin Service Details → Open workspace | You land inside the customer's workspace; AdminSSO in the Module Log |
| 8 | Force the daily cron (command above) | DailyCronJob.UsageRefreshed in the log; balances unchanged (all safety nets no-op) |
| 9 | Open Swarmz dashboard → Settings → Plans → Credit packs | The pack you sold shows its Sold count ticked up (module ≥ 1.19.0) |
If any step misbehaves, the Module Log entry for that action carries the exact request and response — start there.
Make the panel yours — layouts, colors, languages
Since module v1.16.0 the customer-facing service panel is styled from Reseller Console → Appearance — visual preview cards, no code, no template edits:
- Six layouts, each a structurally different composition (not a re-skin): Classic (quiet neutral cards), Swarmz (flat hairline dashboard, like the Swarmz console), Cupertino (Apple-soft: centered hero, extra-round cards), Pulse (bold color-block hero with a featured balance card), Carbon (a dark, dense console with row-style widgets), and Editorial (boxless, typographic, airy).
- Accent: six color schemes (mono, orange, green, red, blue, pink), a per-layout default, or an exact brand hex that overrides everything.
- Languages: the panel renders in the customer's WHMCS language automatically — English, German, French, Italian, Spanish — with your custom credit term woven into the translated labels.
What the customer sees, on every layout:
- Balance cards only for the pools their plan actually includes (plus purchased top-ups whenever they own any — remaining vs. purchased with the 12-month validity note). No empty placeholder boxes.
- Plan limits as a slim one-line strip, not cards.
- A Buy more button opening a designed popup that lists only your mapped credit packs — name, credits, price, one-time vs monthly — ordering through the checkout flow you picked.
Updating the module
The console checks for new releases and shows an Updates page: it downloads the official release, verifies its checksum, backs up the live module folders, warns about any files you hand-edited, and installs on an explicit click. Settings, mappings, and customer data are never touched. (Manual route still works: unzip the release over the WHMCS root.)
File permissions — set up once
The in-console updater writes as the user PHP runs as (find it under WHMCS admin → Utilities → System → PHP Info). Both module folders — and every file inside them — should be owned by that user:
chown -R youruser:youruser /path/to/whmcs/modules/servers/swarmz /path/to/whmcs/modules/addons/swarmz
find /path/to/whmcs/modules/servers/swarmz /path/to/whmcs/modules/addons/swarmz -type d -exec chmod 755 {} +
find /path/to/whmcs/modules/servers/swarmz /path/to/whmcs/modules/addons/swarmz -type f -exec chmod 644 {} +The modules/ directory itself must also be writable by that user (the updater creates its backup folder there — the same ownership rule covers it on a normal install).
Never make module folders world-writable
777 "fixes" the preflight but hands every local process on the server the
ability to replace PHP that WHMCS executes. Ownership is the correct fix —
if PHP runs as nobody/www-data on your setup, switch the domain's PHP
handler to one that runs as the account user (PHP-FPM / LSAPI, the modern
cPanel default), or simply keep updating by ZIP upload, which needs no
special permissions.
Wrong ownership shows up two ways: the Updates preflight flags the folders as not writable, or — if read access broke too — the console reports the provisioning module as unreadable/missing even though the folder is right there. Both have the same fix above; namei -l /path/to/whmcs/modules/servers/swarmz/lib/Api.php shows exactly which path element denies access.
Prompt Box — capture the first prompt on your own site
Since module v1.9.0, the Reseller Console ships an embeddable Prompt Box: one <script> tag on any page of your site — plain HTML, WordPress, any landing builder — renders a themeable prompt widget. A visitor types the app they want, optionally picks a plan inline, and lands in your WHMCS cart with the prompt riding along. When the order provisions, the module passes it to platform-create as initial_prompt — and your customer's first login opens the editor with that app already building.
<script src="https://YOUR-WHMCS/modules/addons/swarmz/promptbox.php?a=js"
data-pid="12"
data-button="Start building"
data-placeholder="Describe the app you want to build…"
data-theme="auto"
data-accent="#4f46e5"
async></script>- Get the code from the console. The Prompt Box view (Reseller Console toolbar) has a snippet builder with a live preview and a log of recently captured prompts and their journey (Captured → Ordered → Provisioned). Its product dropdown fills
data-pidfor you — you never need to look an id up. - One product or many.
data-pidtargets one WHMCS product. To offer plans inline, adddata-plans='[{"pid":12,"label":"Starter","price":"$9/mo"},{"pid":13,"label":"Pro","price":"$29/mo"}]'— each entry maps a label to one of your products. - Free-instance flow. Point the widget at a
$0.00product with instant activation and the whole journey is: type a prompt → quick signup → workspace spins up already building it. Instant activation for a$0.00product means the product's Module Settings must use "Automatically setup the product as soon as an order is placed" — the "first payment is received" option never fires for a zero-amount order (there is no payment event), so the order sits Pending forever, nothing provisions, and the customer's editor button refuses to sign them in until an admin manually accepts the order. - Isolated and dependency-free. The widget renders in a Shadow DOM (your page's CSS can't break it), matches light/dark automatically (
data-theme="auto"), and is unbranded — your accent color, your button label. - Bounded by design. The capture endpoint is public but rate-limited per IP, capped at 10,000 characters, only accepts your Swarmz-module products, and prompts are retained for 30 days.
Custom prompt box — your own UI, same plumbing
If the widget doesn't match your storefront's design, keep your own prompt UI and call the same endpoint the widget uses. It is public (CORS *, no auth), so a plain fetch from your marketing site works:
const res = await fetch(
"https://YOUR-WHMCS/modules/addons/swarmz/promptbox.php?a=intent",
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ prompt: text, pid: 12 }),
},
);
const body = await res.json();
if (res.ok && body.ok) {
window.location.assign(body.redirect); // WHMCS cart, prompt riding as ?swzp=…
} else {
window.location.assign("https://YOUR-WHMCS/cart.php?a=add&pid=12"); // plain cart
}A successful response is:
{ "ok": true, "token": "3f9c…", "redirect": "https://YOUR-WHMCS/cart.php?a=add&pid=12&swzp=3f9c…" }pid is the WHMCS product id of the plan the prompt should order — the number in that product's cart link (cart.php?a=add&pid=120), also shown as [#120] in the console snippet builder's product dropdown. It must be a product whose Module Name is Swarmz; any other id is rejected as unknown_product.
Navigate the visitor to redirect verbatim — the prompt text stays server-side in WHMCS; only the opaque token travels. Failures return { "ok": false, "error": … } with 429 rate_limited (per-IP hourly cap) or 422 for empty_prompt, unknown_product (the pid is not a Swarmz-module product) and storage_unavailable.
Always fall back to your plain cart URL on any failure — a prompt-box hiccup should degrade to a normal order, never a dead button. Everything after the redirect (cart binding, provisioning hand-off, first-login autostart) is identical to the widget path.
How the prompt-to-workspace mechanics work platform-side (consumption on first login, idempotency, the feature kill switch) is documented at Initial prompt.
Frictionless onboarding — swarmz.net-style signup
Since module v1.21.0, Frictionless onboarding takes a visitor straight from a prompt to a building app in one step — the swarmz.net / Lovable signup feel, on your own WHMCS store. The visitor types a prompt, a signup popup asks for just an email and a password, and they land in the builder watching that app already being built. Swarmz creates the WHMCS client account behind the scenes; address and billing details aren't asked for until the customer's first paid order.
Since module v1.22.0 the signup step is a real popup — a centered, accessible modal over your page — and everything about it can be restyled, re-worded, or replaced entirely with a popup you design yourself. Three levels, most-to-least turnkey:
- Use the built-in popup as-is — it's polished, keyboard-accessible, and matches your accent color out of the box.
- Restyle it — every label via
data-*attributes, every color and radius via CSS custom properties, every element addressable from your own stylesheet. See Design the popup. - Replace it — headless mode hands you a tiny JS API and events; you build the entire popup in your own markup and design. See Bring your own popup. (Building the whole prompt box yourself too, with no widget at all? Skip to calling the endpoint directly.)
This assumes the product the prompt box orders is already wired up the normal way — Module Name set to Swarmz, in a server group, with a plan selected (see Plan selection) — since frictionless onboarding places a real order behind the scenes, the same as any other Prompt Box order. Turn it on:
Switch it on
Open Reseller Console → Prompt Box — the Frictionless onboarding card sits above the snippet generator. Switch it on (it's off by default). Two optional settings live on the same card:
- Terms URL — when set, the popup adds an "I agree to the terms" checkbox the visitor must check before their account is created, linking to your terms page. Custom UIs must send
tos: truefor the same effect. - Minimum password length (module ≥ 1.22.0) — enforced server-side on every signup, whichever UI collected it, and mirrored in the built-in popup's hint. Default 8, allowed range 6–64.
Nothing else to set up
The <script> embed you already have on your site needs no changes — the popup appears automatically once the toggle is on. The widget script is served uncached, so the toggle reaches every new page load immediately; a visitor already sitting on a loaded page keeps the mode they loaded with until they reload. Haven't embedded the Prompt Box yet? Follow Prompt Box first; frictionless onboarding is an option on top of it, not a separate embed.
How it works
Everything happens in one server-side request — the visitor never sees a WHMCS page. What you'll find in WHMCS afterwards is exactly what a normal order leaves behind:
- The client account is created from just the email and password (
AddClientwithskipvalidation). The first name is derived from the email and the last name is a generic placeholder — the customer corrects both whenever they next touch their details, typically at their first paid checkout. WHMCS's standard new-account welcome email still goes out. - A
$0order is placed and immediately accepted (AddOrder, thenAcceptOrderwithautosetup), which provisions the tenant the same way any order does: the service goes Active, and its Swarmz Tenant ID and Swarmz Dashboard URL custom fields fill in. The order and invoice emails WHMCS would normally send are suppressed for this one order. When you have an offline payment gateway active (bank transfer or mail-in), the order uses it in preference to a remote gateway — nothing needs to charge on a$0order, and offline gateways run no third-party code during signup. - The prompt rides along: it's bound to the new service before provisioning runs, so Initial prompt applies — the customer's first login opens the editor with that app already building.
- Sign-in is immediate, the same mechanism as platform-sso: the response carries a single-use link straight into the builder.
- It shares the classic capture endpoint's per-IP rate limiter, but with a lower ceiling — 10 per hour — since this path also creates a WHMCS account. Works on WHMCS 8.x and 9.x, same as the rest of the module.
Since v1.22.1 the flow also survives other modules misbehaving: WHMCS runs every active order/fraud/gateway hook inside AddOrder and AcceptOrder, and a third-party module crashing there used to be able to strand the order. The module now contains such crashes, recovers the just-placed order, and carries on to activation — and it records which file crashed, so the offending module is identifiable (see When something goes wrong).
The $0 order is auto-accepted — fraud screening does not run
Frictionless onboarding calls AcceptOrder automatically so the order
provisions without anyone visiting a checkout page. That skips any
fraud-screening module you have configured, for this order only. Every
order after it — an upgrade, a renewal, a credit pack — still goes through
your normal checkout and fraud checks.
An existing email is asked to log in, never signed in automatically
If the email a visitor enters already belongs to a WHMCS client — or to a
WHMCS user left behind by a deleted client, which WHMCS keeps — Swarmz
does not create a second account or sign anyone in automatically. The
popup switches to a "welcome back" state with a link to your login page,
and custom UIs receive account_exists to do the same.
Billing details are collected at the first paid order
Frictionless onboarding only asks for an email and a password. Address, phone, company, and payment details are requested by WHMCS the normal way, the first time the customer checks out for a paid plan, an upgrade, or a credit pack.
Design the popup — copy, colors, and your own stylesheet
Since module v1.22.0, the built-in popup is fully themeable without replacing it.
Every string is a data-* attribute on the embed tag:
<script src="https://YOUR-WHMCS/modules/addons/swarmz/promptbox.php?a=js"
data-pid="12"
data-express-title="Create your account"
data-express-subtitle="One step and your app starts building."
data-email-label="Email address"
data-email-placeholder="you@example.com"
data-password-label="Password"
data-password-placeholder="At least 8 characters"
data-express-button="Create account & start building"
data-login-text="Already have an account? Log in"
data-terms-text="I agree to the terms"
async></script>Every color, radius, and font is a CSS custom property. The widget renders in a shadow root, but custom properties inherit through it — set them on the element the widget mounts into (or any ancestor, including :root) and the whole widget, popup included, repaints:
#signup-box {
--spb-accent: #ff6a00; /* buttons, focus rings, links */
--spb-bg: #101014; /* prompt-box card */
--spb-fg: #f4f4f6; /* text */
--spb-muted: #9a9aa3; /* secondary text */
--spb-border: #26262c; /* input + card borders */
--spb-input-bg: #1a1a20; /* input fields */
--spb-modal-bg: #17171c; /* popup card */
--spb-overlay: rgba(8,8,12,.62); /* dimmed backdrop */
--spb-btn-fg: #ffffff; /* button text */
--spb-radius: 14px; /* popup corner radius */
--spb-font: "Inter", system-ui, sans-serif;
}(--spb-chip styles the inline plan chips when you use data-plans.)
Every element carries a stable class you can target from your own stylesheet for anything the properties don't cover: spb (the prompt-box card), spb-field, spb-go, and inside the popup spb-overlay, spb-modal, spb-title, spb-sub, spb-context (the "Building: …" line), spb-label, spb-input, spb-tos, spb-submit, spb-modal-err, spb-login-link, spb-checkout-link, spb-close. These names are part of the module's compatibility contract — they don't change between releases.
Bring your own popup — headless mode
Since module v1.22.0, add data-express-mode="headless" to the embed and the widget renders the prompt box but no popup at all — your page provides the entire signup UI, in your own markup, styles, and animation, while the widget keeps doing the plumbing:
<script src="https://YOUR-WHMCS/modules/addons/swarmz/promptbox.php?a=js"
data-pid="12" data-express-mode="headless" async></script>When the visitor submits a prompt, the widget emits it instead of opening anything — open your own popup then, and when your form submits, hand the details back:
// 1. Visitor submitted a prompt → open YOUR popup.
window.SwarmzPromptBox.on("prompt", ({ prompt, pid }) => {
savedPrompt = prompt;
openMySignupPopup();
});
// 2. Your popup's form submits → the widget does the rest.
const res = await window.SwarmzPromptBox.submit({
prompt: savedPrompt,
email: myEmailInput.value,
password: myPasswordInput.value,
tos: myTermsCheckbox?.checked, // only needed when a Terms URL is configured
});
if (res.ok) {
window.location.assign(res.redirect); // straight into the builder, signed in
} else if (res.error === "account_exists") {
showMyWelcomeBackState(); // link to your login page — never auto-signed-in
} else {
showMyError(res.error); // and offer the classic cart link as a way out
}The same signals are also dispatched as DOM CustomEvents on the embed's <script> element — swarmz:prompt and swarmz:express-result, each with the payload in event.detail — for frameworks that prefer event listeners over callbacks. submit() resolves with exactly the endpoint's response shape ({ ok, redirect } or { ok: false, error } — plus error: "network_error" when the request never reached your WHMCS), so the error table below applies unchanged. One widget per page owns the SwarmzPromptBox API; if you're not rendering the widget's prompt box at all, skip the widget and call the endpoint directly instead:
Custom signup box — call the endpoint yourself
If you're building the whole thing yourself — prompt box and popup, with no widget on the page — call the endpoint directly: POST promptbox.php?a=express. It's public (CORS *, no auth), just like the intent endpoint, except this one also creates the WHMCS account and returns a link straight into a signed-in workspace.
const res = await fetch(
"https://YOUR-WHMCS/modules/addons/swarmz/promptbox.php?a=express",
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
prompt: text,
pid: 12,
email: emailInput.value,
password: passwordInput.value,
tos: tosCheckbox.checked,
}),
},
);
const body = await res.json();
if (res.ok && body.ok) {
window.location.assign(body.redirect); // straight into the builder, already signed in
} else {
// body.error — see the table below — show it inline and offer the classic cart link
}Prop
Type
A successful response is:
{
"ok": true,
"redirect": "https://swarmz.net/sso?token=<jwt>&workspace=<tenant_id>"
}redirect is always an absolute URL — send the browser there directly. Most of the time it's a single-use sign-in link straight into the editor, the same kind platform-sso mints. If sign-in couldn't be completed in time — rare, and the account and order still exist either way — redirect instead points at the client area, where the customer signs in with the email and password they just chose.
Failures return { "ok": false, "error": "<code>" }:
| Status | error | When | What to show |
|---|---|---|---|
| 403 | express_disabled | Frictionless onboarding is off in the console | Fall back to the classic cart link |
| 422 | empty_prompt | prompt is missing, empty, or over the character cap | Ask for a prompt |
| 422 | unknown_product | pid is not a product whose Module Name is Swarmz | Fix the embed/config — this is a setup error |
| 422 | invalid_email | email fails standard validation | Inline "check your email address" |
| 422 | weak_password | password is under the configured minimum, over 256 characters, or whitespace-only | Inline "use at least N characters" |
| 422 | tos_required | A Terms URL is configured and tos was not sent as truthy | Ask the visitor to accept the terms |
| 409 | account_exists | That email already belongs to a WHMCS client, or to a user left behind by a deleted client — no account is created | A "welcome back" state linking to your login page |
| 429 | rate_limited | More than 10 requests from this IP in the last hour | "Too many attempts — try again in a few minutes" |
| 422 | signup_failed | WHMCS could not create the client — the exact reason is in the Module Log, never in this response | Generic error + the classic cart link |
| 422 | order_failed | WHMCS could not place the order (and no just-placed order could be recovered) | Generic error + the classic cart link |
| 422 | storage_unavailable | The prompt could not be stored | Generic error + the classic cart link |
Always give the visitor a way back to the classic checkout on failure — fall back to the plain cart link (cart.php?a=add&pid=…), the same way the built-in popup does, so a signup hiccup is never a dead end.
When something goes wrong
Two places show you exactly what happened, per attempt:
Reseller Console → Prompt Box → Recent express signups lists the last attempts with time, email prefix, and the step each one ended on:
| Step | Meaning |
|---|---|
ok_sso | Signed up, provisioned, and sent straight into the builder — the happy path |
ok_fallback | Account and order created; the sign-in link couldn't be minted in time, so the visitor was sent to the client area to log in |
ok_no_service | Order accepted but the service row couldn't be identified — the account works; the prompt didn't attach |
account_exists | The email already had an account (or a leftover user) — the visitor was asked to log in |
addclient_failed | WHMCS refused to create the client — the reason is in the Module Log |
no_gateway | No active payment gateway to place the order with — activate one |
addorder_failed | WHMCS could not place the order, and nothing recoverable was found |
fatal | An unexpected crash — the note includes the file and line that threw |
Utilities → Logs → Module Log carries the request/response of every step (expresssignup.addclient, .addorder, .acceptorder, …) with the password always stripped. Since v1.22.1, when another module's hook or gateway code crashes inside a WHMCS order call, the entry includes thrown_at — the exact file and line of the module that crashed. The signup rides through such crashes (the order is recovered and still activated), but a module crashing during order processing is worth fixing or disabling regardless: it likely affects your normal checkout too.
Customer sign-in and usage
In the client area, the module adds an Open AI Editor button (rename it in the console). It calls platform-sso, mints a short-lived redirect, and drops the customer into their dashboard already logged in — a fresh token on every click, nothing cached. Since v1.9.0 the module retries transient network and gateway blips automatically, and any refusal (suspended, cancelled, still provisioning) renders as a plain-language, unbranded message with a next step instead of a raw error code.
Since v1.11.0 your staff get the same one-click entry: the admin Service Details tab of any Swarmz service has an Open workspace (signs you in) button that mints a fresh admin SSO redirect and lands you inside the customer's workspace — for support sessions, no password juggling. (The plain dashboard URL is still shown for reference, labeled unauthenticated.) Requires the Reseller Console addon to be active; every sign-in is logged as AdminSSO in the Module Log.
The Reseller Console reads platform-usage and shows each customer's plan and live consumption in one table, so you can reconcile against your wholesale invoice. Its settings also control client-area presentation: the editor button label, what you call "credits", and whether to show AI and cloud spend to the customer. See Usage and Billing summary.
Troubleshooting
Calls return 409 account_inactive
Your platform account isn't active yet. A card on file is the gate — contact
us to activate it. Until then, create and sso are blocked by design.
- Test Connection fails with 401 — the key is wrong, rotated, or not set. Paste the current
sk_live_…key into the console's API Key (or the server's Password). See Authentication. - Nothing provisions when an order is accepted — open the product's Module Settings and confirm Module Name is Swarmz and a Server Group is selected.
- A
$0.00order sits in Pending and never provisions — the product's setup option is "when the first payment is received", which never fires for a zero-amount order. Switch it to "Automatically setup the product as soon as an order is placed" (or accept the pending order manually once). While a service is Pending, the customer's Open AI Editor button is refused by design. - Customer can't open the editor — the tenant is likely suspended; SSO returns
409 suspendeduntil you unsuspend. - Want to see what was sent — every call is recorded under Utilities → Logs → Module Log (the API key is redacted).
Prefer to build it yourself?
Not on WHMCS, or wiring provisioning into your own panel? Every action above is a plain REST call. Start at Authentication and Create a tenant.
WHMCS setup walkthrough
From an empty WHMCS to selling Swarmz plans and credit packs — every click, in order, with nothing assumed. Follow it once, top to bottom, in about 30 minutes.
Create a tenant
Provision a fully-isolated Swarmz workspace for one of your customers. Maps to WHMCS CreateAccount and is idempotent on your external reference.