Swarmz

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.

RequirementMinimumUsed for
WHMCS8.x or newerModule APIs, hooks, client-area templates
PHP8.1 or newerThe module is modern, plain PHP — no encoders
curl extensionenabledEvery Swarmz API call, and downloading updates
json extensionenabled (bundled with PHP 8)API request and response bodies
mbstring extensionenabledSafe text handling — prompts, release notes, translations
zip extension (ZipArchive)enabled — auto-updater onlyExtracting 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.netAll platform calls. On a private endpoint? Allow that host instead
Outbound HTTPS for updatesto api.github.com, github.com, *.githubusercontent.comThe auto-updater's release check and download (release assets redirect to githubusercontent.com)
File ownershipmodule folders owned by the PHP user — dirs 755, files 644The one-click auto-updater. Set it once: File permissions
Swarmz accountactive, with your sk_live_… keyA 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 through curl.
  • 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 Console

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

FieldValue
NameSwarmz (anything you like)
Hostnameapi.swarmz.net
ModuleSwarmz
Usernameleave blank
Passwordleave 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 eventCallsEffect
Accept order / Createplatform-createProvisions the tenant on the selected plan (plan_code); stores its id + dashboard URL
Upgrade / Downgrade (Change Package)platform-planRe-assigns the new plan by plan_code; the platform prorates the switch server-side
Renewal invoice paid (InvoicePaid)platform-plan-refreshRolls the credit cycle at the billing boundary — resets monthly credits, applies rollover
Credit-pack addon invoice paid (InvoicePaid, module ≥ 1.11.0)platform-topupAdds the mapped pack's credits to the customer's workspace — once per paid invoice
Suspendplatform-suspendPauses compute + cloud, unpublishes sites, blocks SSO
Unsuspendplatform-unsuspendResumes compute + cloud, republishes sites
Terminateplatform-terminatePermanent teardown
Client clicks Open AI Editorplatform-ssoMints a fresh redirect and logs the customer in
Client area / Console usageplatform-usageReads 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. CreateAccount and ChangePackage fail 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 $0 pack 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-fired InvoicePaid hook, 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-refresh anchored 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 on whmcs-inv<invoiceid>-ha<addonid>.

Daily: DailyCronJob

One reconciliation pass per day, inside WHMCS's daily automation run:

  1. Usage refresh — a single account-wide platform-usage call, cached onto every service, so the client area shows live credit / cloud numbers instantly.
  2. 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.
  3. 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.
  4. 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).
  5. 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 --force

Test the money paths

A 15-minute end-to-end pass against a test client, in the order the money flows:

#DoExpect
1Order the product, pay/acceptService Active; custom fields Swarmz Tenant ID + Dashboard URL filled; Open AI Editor signs the client in
2Order a mapped credit pack with the productCredits appear on the workspace right after provisioning (CreditPack.Granted in the Module Log); balance visible in the client area
3Buy a pack standalone, pay the invoiceCredits land within seconds of payment
4Pay the same invoice again (Mark Unpaid → Add Payment)No second grant — the log shows the call, the balance doesn't move
5Client-area Upgrade to a higher product, pay the prorated invoiceChangePackage in the log; workspace immediately gains the prorated credit difference; your wholesale meter shows exactly that amount
6Downgrade backNew caps apply immediately, nothing clawed back, no wholesale charge; full effect at next renewal
7Admin Service Details → Open workspaceYou land inside the customer's workspace; AdminSSO in the Module Log
8Force the daily cron (command above)DailyCronJob.UsageRefreshed in the log; balances unchanged (all safety nets no-op)
9Open Swarmz dashboard → Settings → Plans → Credit packsThe 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-pid for you — you never need to look an id up.
  • One product or many. data-pid targets one WHMCS product. To offer plans inline, add data-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.00 product with instant activation and the whole journey is: type a prompt → quick signup → workspace spins up already building it. Instant activation for a $0.00 product 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:

  1. Use the built-in popup as-is — it's polished, keyboard-accessible, and matches your accent color out of the box.
  2. 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.
  3. 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: true for 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 (AddClient with skipvalidation). 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 $0 order is placed and immediately accepted (AddOrder, then AcceptOrder with autosetup), 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 $0 order, 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>" }:

StatuserrorWhenWhat to show
403express_disabledFrictionless onboarding is off in the consoleFall back to the classic cart link
422empty_promptprompt is missing, empty, or over the character capAsk for a prompt
422unknown_productpid is not a product whose Module Name is SwarmzFix the embed/config — this is a setup error
422invalid_emailemail fails standard validationInline "check your email address"
422weak_passwordpassword is under the configured minimum, over 256 characters, or whitespace-onlyInline "use at least N characters"
422tos_requiredA Terms URL is configured and tos was not sent as truthyAsk the visitor to accept the terms
409account_existsThat email already belongs to a WHMCS client, or to a user left behind by a deleted client — no account is createdA "welcome back" state linking to your login page
429rate_limitedMore than 10 requests from this IP in the last hour"Too many attempts — try again in a few minutes"
422signup_failedWHMCS could not create the client — the exact reason is in the Module Log, never in this responseGeneric error + the classic cart link
422order_failedWHMCS could not place the order (and no just-placed order could be recovered)Generic error + the classic cart link
422storage_unavailableThe prompt could not be storedGeneric 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:

StepMeaning
ok_ssoSigned up, provisioned, and sent straight into the builder — the happy path
ok_fallbackAccount 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_serviceOrder accepted but the service row couldn't be identified — the account works; the prompt didn't attach
account_existsThe email already had an account (or a leftover user) — the visitor was asked to log in
addclient_failedWHMCS refused to create the client — the reason is in the Module Log
no_gatewayNo active payment gateway to place the order with — activate one
addorder_failedWHMCS could not place the order, and nothing recoverable was found
fatalAn 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.00 order 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 suspended until 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.

On this page