A WHMCS addon module that pushes your WHMCS communications through Silon:
- All WHMCS email through Silon — via Silon's SMTP submission gateway.
- WhatsApp notifications on billing events — new client, order confirmed, invoice created/paid, service activated/suspended — sent through the Silon API using your approved WhatsApp templates.
- Client identity verification (OTP) — before a sensitive operation (e.g. a domain transfer), an operator sends a one-time code to the client's phone via SMS or WhatsApp and confirms the code the client reads back.
Built on the official silon/silon-sdk
PHP SDK.
- WHMCS (admin access to Configuration → Addon Modules)
- PHP 8.1+
- A Silon API key (
sk_live_…) and workspace (or a self-hosted base URL)
-
Copy the module into your WHMCS install:
cp -r modules/addons/silon /path/to/whmcs/modules/addons/ -
Pull in the SDK (creates
vendor/):cd /path/to/whmcs/modules/addons/silon composer install --no-devNo Composer on the server? Download a release bundle that already includes
vendor/, or runcomposer installlocally and upload thevendor/folder. -
In WHMCS: Configuration → System Settings → Addon Modules, find Silon, click Activate, then Configure and fill in your API key and workspace.
Open the addon (Addons → Silon) for a dashboard that live-tests the connection, shows your email/SMTP status, and lets you send test messages.
WHMCS renders and sends its own email (invoices, welcome, password resets, …). The cleanest way to send all of it through Silon is WHMCS's native SMTP support pointed at the Silon gateway. In Configuration → System Settings → General → Mail (older WHMCS: Setup → General Settings → Mail):
| Field | Value |
|---|---|
| Mail Type | SMTP |
| Host | smtp.silon.tech |
| Port | 587 (STARTTLS) or 465 (TLS) |
| Username | apikey |
| Password | your Silon API key |
The addon dashboard shows whether WHMCS is currently pointed at Silon and displays these values pre-filled with your key.
Why SMTP and not the API? WHMCS's email hooks don't expose the fully rendered message body at a point where the native send can be replaced, so intercepting every email through the API isn't reliable. SMTP captures every email with full fidelity (HTML,
Cc/Bcc,Reply-To, attachments) — which is exactly what the Silon SMTP gateway is for.
Turn on WhatsApp notifications in Configure, then open Addons → Silon to map templates. The dashboard fetches your approved WhatsApp templates live from Silon — no template names to copy by hand.
For each event you get:
- a dropdown of your approved templates (with language + category); pick one, or leave it off;
- a variable-binding row for each
{{n}}slot the chosen template declares — bind it to a WHMCS field (client first name, invoice number, total, product, domain, …). Sensible defaults are filled in automatically when you pick a template, so it works out of the box and you only adjust what you need.
| Event | WHMCS hook | Default bindings |
|---|---|---|
| New client | ClientAdd |
first name |
| Password changed | ClientChangePassword |
first name |
| Order confirmed | AcceptOrder |
first name · order number · total |
| Order paid | OrderPaid |
first name · order number · total |
| Order cancelled | CancelOrder |
first name · order number |
| Invoice created | InvoiceCreated |
first name · invoice no · total · due date |
| Invoice paid | InvoicePaid |
first name · invoice no · total |
| Invoice payment reminder | InvoicePaymentReminder |
first name · invoice no · total · due date |
| Invoice cancelled | InvoiceCancelled |
first name · invoice no |
| Invoice refunded | InvoiceRefunded |
first name · invoice no · total |
| Service activated | AfterModuleCreate |
first name · product · domain |
| Service suspended | AfterModuleSuspend |
first name · product · domain |
| Service unsuspended | AfterModuleUnsuspend |
first name · product · domain |
| Service terminated | AfterModuleTerminate |
first name · product · domain |
| Service up/downgraded | AfterModuleChangePackage |
first name · product · domain |
| Cancellation requested | CancellationRequest |
first name · product · domain |
| Domain registered | AfterRegistrarRegistration |
first name · domain name |
| Domain transferred in | AfterRegistrarTransfer |
first name · domain name |
| Domain renewed | AfterRegistrarRenewal |
first name · domain name |
| Ticket opened | TicketOpen |
first name · ticket no · subject |
| Ticket replied (staff) | TicketAdminReply |
first name · ticket no · subject |
| Ticket closed | TicketClose |
first name · ticket no · subject |
A hook name that doesn't exist on your WHMCS version simply never fires — the catalog is safe across versions. Ticket replies carry no idempotency key (they recur per ticket); every other event double-fires safely.
Three staff-facing events alert your team instead of the client: Ticket
opened → staff (TicketOpen), Customer replied → staff (TicketUserReply),
and New order placed → staff (AfterShoppingCartCheckout). A ticket from an
unregistered email still alerts staff.
Recipients mirror WHMCS's own admin-email rules, resolved live at dispatch time: ticket events go to active admins whose role has Support Emails on and who subscribed to the ticket's department in their profile; order events go to admins whose role has Account Emails on. The addon dashboard's Staff notification numbers table lists every active admin with their effective email-rule status — add a WhatsApp number to include them (WHMCS has no phone field for admins; admins matched by the rules but without a number are noted in the Module Log). Additional numbers (shared ops phones) can be appended globally or per department.
Everything meaningful leaves a trace. Module Log (Utilities → Logs): every send with its outcome, and every mapped event that fired but delivered nothing, with the reason — unresolvable records, no usable client phone, matched admins without numbers, invalid E.164 entries. (Deliberately unmapped events stay silent.) Client Activity Log: OTP code sent and verified entries, with channel, number, and the operator's reason.
The template's language is taken from the template itself; an optional
provider slug is set once in Configure. Business-initiated WhatsApp
requires Meta-approved templates — create and approve them in your Silon
dashboard first; only APPROVED templates appear in the dropdowns. The mapping
is stored in the addon's own mod_silon_config table and survives
deactivate/reactivate. Use Send a test WhatsApp on the dashboard to verify a
template delivers (its variables are filled with placeholder text).
Messages go to the client's phone in E.164 (+<country><number>). The addon
uses WHMCS's pre-formatted international number when available; otherwise it
derives the calling code from the client's country, falling back to the
Default calling code you configure (e.g. 965). Clients with no usable
number are skipped.
- Hooks are fully guarded — a Silon or network error is logged (Utilities → Logs → Module Log) and never disrupts billing.
- Each notification carries a stable idempotency key
(
whmcs-<event>-<id>), so a hook that fires twice never double-sends.
A customer calls in and asks you to transfer a domain — how do you know it's really them? The addon puts Silon's OTP API behind a two-step form in the admin area:
- Open the client's profile — an Identity verification (Silon OTP) panel sits right on the summary page (send → enter code → verified, in place, no page change). There's also a Verify identity (Silon OTP) link under Other Actions that opens the full-page flow, and you can start from the addon dashboard with a client ID.
- Pick the channel — SMS or WhatsApp — confirm the phone (pre-filled
from the client's profile, in E.164), optionally note a reason
(e.g.
domain transfer example.com), and click Send code. - The client receives the code and reads it back to you (over the phone, in chat — however you're talking to them).
- Type the code into the verify form. On a match you get a green Identity verified confirmation and an entry in the client's Activity Log (with your reason), and you can proceed with the operation.
A wrong code shows how many attempts remain; when the attempts are exhausted or the code expires, the form loops back to sending a fresh code. Code length, expiry, attempt limits, and per-recipient send caps are all enforced by Silon — configure them on the purpose, not in WHMCS.
- In your Silon workspace, create the OTP purposes (one per channel you
want to offer):
whmcs-verify-sms— channel SMS;whmcs-verify-whatsapp— channel WhatsApp, which requires an approved AUTHENTICATION-category template (Meta's OTP template type).
- In the addon Configure screen, tick Identity verification (OTP).
On Silon servers that expose
GET /api/v1/otp/purposes/the two purpose fields render as dropdowns of your live purposes (filtered by channel); on older servers they are free-text and default to the names above. Leaving a purpose blank/off hides that channel from the operator. - Your API key needs the
otp:sendandotp:verifyscopes.
With an sk_test_ key nothing is dispatched and the magic code 000000
verifies — handy for trying the flow end to end.
In Configure (WHMCS addon settings):
| Field | Notes |
|---|---|
| API key | sk_live_ / sk_test_ |
| Workspace | acme → https://acme.silon.tech |
| Base URL | overrides Workspace (self-hosted Silon) |
| WhatsApp notifications | master on/off |
| Default calling code | digits only, e.g. 965 |
| WhatsApp provider | optional slug (e.g. meta_cloud) |
| Identity verification (OTP) | master on/off for the operator verify flow |
| OTP purpose — SMS | Silon purpose name with channel SMS (blank hides SMS) |
| OTP purpose — WhatsApp | Silon purpose name with channel WhatsApp (blank hides WhatsApp) |
The per-event template + variable mapping is configured in the addon dashboard (Addons → Silon), not here — it's built from your live approved templates.
Pure logic (phone normalisation, event→payload mapping) is dependency-free and unit-tested — no WHMCS or SDK required:
php tests/run.php
Lint everything with php -l modules/addons/silon/**/*.php. The SDK-facing code
is exercised against the real silon/silon-sdk classes.
MIT