Send email from WHMCS with Volanea by adding a small server-side PHP hook that runs when WHMCS creates a client record. This approach uses WHMCS’s native hook system and Volanea’s REST API—there is no native Volanea WHMCS app or marketplace plugin to install.
The practical example in this guide sends a welcome email when the ClientAdd hook point runs. It is a useful starting point because WHMCS provides the new client’s name, email address, client ID, email preferences, and other fields to the hook. The same pattern can later be adapted for paid invoices, service provisioning, ticket updates, domain events, or other WHMCS hook points.
What the integration actually uses
WHMCS has a native scripting layer called Hooks. A hook is PHP code that WHMCS executes at a named point in its application lifecycle. Hook files can live in the /includes/hooks/ directory, where WHMCS discovers and loads them. That means a self-hosted WHMCS installation can make an outbound HTTPS request directly from server-side PHP.
This is importantly different from a no-code outbound-webhook product. WHMCS does not post a generic, preconfigured outbound webhook for ClientAdd that you simply paste into a URL field. Instead, it invokes your PHP callback and passes an array of variables. Your callback builds the Volanea JSON request and posts it to https://api.volanea.com/v1/send.
For this integration, the path is:
- A client is added in WHMCS through the client area, admin area, API, or another workflow that creates a client.
- WHMCS executes the
ClientAddhook point. - The hook receives the client variables in PHP.
- The hook maps approved values into a Volanea transactional-email request.
- Volanea accepts the message for processing and returns an HTTP response.
This is a direct server-to-server integration. The Volanea secret key never needs to be exposed to the client browser, an order-form template, JavaScript, a public webhook URL, or a client-visible configuration screen.
The concrete WHMCS trigger: ClientAdd
The example trigger is ClientAdd, which WHMCS documents as executing as a client is being added. It is a record-creation event, not merely a page view or a form-submit event. That distinction matters: the email is tied to the creation of a client record rather than to a front-end page that could be refreshed or abandoned.
WHMCS passes a variable array to the hook. Relevant fields include:
client_id: the ID of the client that was added.user_id: the user ID associated with that client.userid: another client ID field supplied by this hook point.firstnameandlastname: the client’s name fields.email: the client email address.companyname,country,customFields, and other client-profile values.emailoptoutandmarketing_emails_opt_in: preference-related values that can influence the type of email you should send.
A welcome email confirming account creation is generally transactional. Do not silently turn this hook into a marketing campaign trigger. Marketing messages have different consent, unsubscribe, and compliance requirements. If you want to use a marketing preference in a transactional flow, use it to control optional promotional content—not to suppress essential account or billing messages that a customer needs.
The hook array is not an HTTP webhook payload
It is worth being precise about terminology. At ClientAdd, WHMCS sends the following data to your PHP callback inside the WHMCS process. It does not automatically JSON-encode and transmit this shape to Volanea.
A representative subset of the variables looks like this:
$vars = [
'client_id' => 4821,
'user_id' => 7754,
'userid' => 4821,
'firstname' => 'Avery',
'lastname' => 'Nguyen',
'companyname' => 'Northstar Hosting',
'email' => 'avery@example.com',
'country' => 'US',
'emailoptout' => false,
'marketing_emails_opt_in' => true,
'customFields' => [],
];
Your hook should map only the fields it needs. In a welcome email, that normally means client_id, firstname, lastname, and email. Sending the entire hook array externally is unnecessary and can disclose personal data such as phone numbers, addresses, notes, tax fields, passwords, or custom fields.
Before you write code
Complete the sending prerequisites first. The code can be correct and still fail if the sending identity is not ready.
Verify the sending domain in Volanea
Use a From address at a domain you have verified in Volanea, such as billing@yourcompany.com or support@yourcompany.com. Domain verification establishes that your account is authorized to send as that domain and enables the authentication configuration associated with it.
Do not use an arbitrary customer domain, an address copied from a client profile, or a From address that only exists in a local mail client. Your From address is your business identity; keep it stable, recognizable, and aligned with the domain your customers expect.
Create a secret API key
Create a Volanea secret key for the server-side integration. The REST send endpoint uses a secret key in the Authorization header. Treat that key like a password with permission to send email through your account.
Keep the key separate by environment when possible. A staging WHMCS instance should use a staging or restricted test key rather than the credential used by production billing operations. This prevents test signups from reaching real customers and makes it easier to revoke credentials without interrupting every environment.
For endpoint details, supported message fields, and future extensions such as templates or attachments, keep the email API reference and setup guides nearby while implementing the integration.
Choose a clear transactional message
A first email should have a single job. For example: confirm that a client account was created, explain the next safe step, and direct the customer to the client area through a known URL.
Avoid putting raw passwords, full payment information, server credentials, or sensitive client notes in this message. The ClientAdd hook documentation includes a password field in its available variables, but this integration deliberately never reads, logs, transforms, or transmits it.
Where the Volanea API key belongs
Put the Volanea secret in server-only configuration available to the PHP process that runs WHMCS. The preferred pattern is an environment variable such as VOLANEA_API_KEY configured in PHP-FPM, Apache, a container secret, or your deployment platform’s secret manager.
The hook retrieves it with getenv('VOLANEA_API_KEY'). This separates code from credentials: you can deploy the same hook file to staging and production while each environment supplies its own key.
A workable alternative for installations without environment-secret management is defining a custom constant in WHMCS’s configuration.php file and reading that constant from the hook. WHMCS identifies configuration.php as a sensitive configuration file and recommends protecting its permissions. Use this as a server configuration option—not as a value to print in a template, store in an order-form field, add to a client-area JavaScript bundle, or enter into a custom field visible to clients.
Why browser-visible configuration is unsafe
A front-end user can inspect JavaScript, HTML, browser network requests, public repository history, source maps, and client-side environment variables. Any Volanea key placed there can be copied and used by someone else to send mail through your account.
The same rule applies to public middleware endpoints. If you create an endpoint between WHMCS and Volanea, the Volanea key must remain on that endpoint’s server. WHMCS should authenticate to the endpoint with a separate secret or signed request, and the endpoint should validate the request before it calls Volanea.
Keep secrets out of logs
Do not log the Authorization header, the API key, full request bodies containing sensitive content, or a client password. Logs should be useful for operations without becoming a second database of credentials and customer data.
For the example below, log only a narrow operational result: the WHMCS client ID, HTTP status code, and a short error category. WHMCS makes activity logging available to hooks, which is useful for confirming that the hook ran while avoiding the temptation to dump the complete response or request.
Working PHP hook: map ClientAdd to Volanea
Create a file named something descriptive, such as:
/includes/hooks/volanea-client-welcome.php
Then add the following code. It uses PHP’s cURL extension to make the direct HTTPS POST. It validates the recipient address, escapes the name in HTML, provides a plain-text fallback, and creates a stable Idempotency-Key from the WHMCS client record and the logical message type.
<?php
if (!defined('WHMCS')) {
die('This file cannot be accessed directly');
}
/**
* Send a transactional Volanea welcome email when WHMCS creates a client.
*
* WHMCS ClientAdd $vars contains, among other fields:
* client_id, user_id, userid, firstname, lastname, email,
* emailoptout, marketing_emails_opt_in, and customFields.
*/
add_hook('ClientAdd', 1, function (array $vars) {
$apiKey = getenv('VOLANEA_API_KEY');
if ($apiKey === false || $apiKey === '') {
logActivity('Volanea welcome email not sent: VOLANEA_API_KEY is not configured.');
return;
}
// Field mapping from WHMCS ClientAdd variables.
$clientId = (int) ($vars['client_id'] ?? 0);
$firstName = trim((string) ($vars['firstname'] ?? ''));
$lastName = trim((string) ($vars['lastname'] ?? ''));
$recipient = trim((string) ($vars['email'] ?? ''));
$fullName = trim($firstName . ' ' . $lastName);
if ($clientId < 1 || !filter_var($recipient, FILTER_VALIDATE_EMAIL)) {
logActivity('Volanea welcome email not sent: ClientAdd payload lacked a valid client ID or email address.');
return;
}
// This is a transactional account-creation email. Do not use this hook
// to send optional marketing content based on marketing_emails_opt_in.
$safeName = htmlspecialchars($firstName !== '' ? $firstName : 'there', ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
$clientAreaUrl = 'https://billing.example.com/clientarea.php';
// Volanea POST /v1/send JSON payload.
$payload = [
'from' => 'Northstar Hosting <support@yourcompany.com>',
'to' => $fullName !== '' ? [$fullName . ' <' . $recipient . '>'] : [$recipient],
'subject' => 'Welcome to Northstar Hosting',
'html' => '<p>Hi ' . $safeName . ',</p>'
. '<p>Your client account has been created.</p>'
. '<p><a href="' . htmlspecialchars($clientAreaUrl, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8') . '">Sign in to your client area</a> to review your services and billing details.</p>',
'text' => 'Hi ' . ($firstName !== '' ? $firstName : 'there') . ",\n\n"
. "Your client account has been created.\n\n"
. 'Sign in to your client area: ' . $clientAreaUrl,
];
// Stable for this business event. Reusing it on a retry avoids a second welcome email.
$idempotencyKey = 'whmcs-client-welcome-' . $clientId;
$curl = curl_init('https://api.volanea.com/v1/send');
curl_setopt_array($curl, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE),
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $apiKey,
'Content-Type: application/json',
'Accept: application/json',
'Idempotency-Key: ' . $idempotencyKey,
],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 5,
CURLOPT_TIMEOUT => 10,
]);
$responseBody = curl_exec($curl);
$curlError = curl_error($curl);
$httpStatus = (int) curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
curl_close($curl);
if ($responseBody === false || $httpStatus < 200 || $httpStatus >= 300) {
$category = $curlError !== '' ? 'network error' : 'HTTP ' . $httpStatus;
logActivity('Volanea welcome email submission failed for WHMCS client ID ' . $clientId . ': ' . $category . '.');
return;
}
logActivity('Volanea welcome email accepted for WHMCS client ID ' . $clientId . ' (HTTP ' . $httpStatus . ').');
});
Replace these values before using the code:
Northstar Hosting <support@yourcompany.com>with a sender on a domain verified in Volanea.https://billing.example.com/clientarea.phpwith the real WHMCS client-area URL.VOLANEA_API_KEYwith the environment-variable name your deployment exposes to PHP, if you use a different name.
What each Volanea request field does
The payload deliberately follows a simple transactional-message structure:
| Volanea field | WHMCS source or application value | Purpose |
|---|---|---|
from | Static server-side value | Identifies your verified sender. |
to | $vars['email'], plus name when available | Delivers the welcome email to the new client. |
subject | Static application value | Gives the message a stable, recognizable subject. |
html | Server-rendered content using escaped firstname | Provides a branded HTML version. |
text | Server-rendered plain-text content | Provides a readable fallback. |
Idempotency-Key header | whmcs-client-welcome- plus client_id | Identifies one logical welcome-email event across retry attempts. |
The to field is an array even though this welcome email has one recipient. That makes its recipient shape explicit and is compatible with the single-send endpoint’s ability to address one recipient or a small recipient list. Do not put multiple customers into the same welcome message. Account-creation email should always be addressed to the individual account holder.
Why idempotency matters for WHMCS email hooks
A transactional email is a real side effect. The difficult scenario is not only a clear API error; it is an ambiguous result. For example, Volanea could accept the request, but the connection between your WHMCS server and Volanea could time out before PHP receives the response. If you blindly make a second request with a new identifier, the customer may receive two welcome emails.
The Idempotency-Key header solves that problem when the same logical send is attempted again. In this guide, whmcs-client-welcome-4821 means “the welcome email for client 4821,” not “the 10:32:17 HTTP request made by a particular PHP process.” The key must remain stable for a retry of the same event.
Do not use uniqid(), a timestamp, or a random UUID as the only idempotency value for this hook. Those values are useful for identifying attempts, but they change on every retry and therefore cannot tell Volanea that two requests represent the same email.
Do not reuse a key for a different message
A stable key should be unique to the business event, not permanent for the client. If you later add a “verify your email address” message, it needs a different key namespace, such as whmcs-email-verification-4821-v1. If an account can be closed and recreated under a new client record, the new client ID naturally separates the events.
For invoice notifications, construct the key from the invoice ID and message type, for example whmcs-invoice-paid-receipt-19384. For provisioning notifications, derive it from the service ID and provisioning event. The goal is that one customer-facing event maps to one idempotency key.
Test the flow safely
Do not start by creating a live customer record and hoping for the best. A small test plan catches setup errors before a real client sees them.
- Verify the sender domain and confirm the From address is permitted in Volanea.
- Set
VOLANEA_API_KEYin the server environment used by the PHP process, then reload PHP-FPM or the relevant service if required by your host. - Place the hook file in
/includes/hooks/with permissions that allow the web server to read it but do not make it broadly writable. - Create a test client using an inbox you control.
- Check the WHMCS activity log for the narrow success or failure message from the hook.
- Check Volanea’s sending activity and event data to distinguish acceptance from downstream delivery behavior.
- Create or repeat the same test carefully to confirm your idempotency behavior rather than generating unnecessary duplicate mail.
A successful 2xx response means Volanea accepted the API submission. It does not, by itself, prove that the message appeared in the inbox. Inbox placement can still be affected by recipient suppression, a recipient server response, authentication alignment, spam filtering, or later bounce and complaint events.
Test an invalid recipient too
The code validates a basic email-address format before calling the API, but syntax validation is not a guarantee that an address exists or can receive mail. Use a known invalid test value only in a controlled environment and make sure your operational process can distinguish a rejected API submission from a later bounce.
For lists collected outside WHMCS or for a customer-data cleanup project, an email address verification tool can help reduce obvious address-quality problems before they reach a transactional workflow. Do not use verification as a substitute for handling Volanea delivery events and customer updates over time.
When this breaks: failures at the WHMCS-to-Volanea hop
Every integration needs a failure policy. The direct PHP hook has a short chain—WHMCS hook, outbound HTTPS, Volanea API—but each stage can fail differently. The right response depends on whether you know the message was not accepted, accepted, or left in an unknown state.
WHMCS repeats an operation and a duplicate email is sent
A hook can run more than once when the originating WHMCS action is repeated, when a client-creation flow is submitted again, when an API caller retries after an error, or when custom automation replays work. Do not assume that “one user intention” always produces one PHP execution.
The stable Idempotency-Key in the code is the duplicate-defense layer for the outbound request. It tells Volanea that any repeat submission for this same client-welcome event represents the same logical email. Keep the key deterministic and do not generate it anew on each execution.
If you later add your own retry queue, pass the original idempotency key into the queue record and reuse it. A retry worker that reconstructs a new random key reintroduces the duplicate-send risk that idempotency was meant to solve.
The API call times out
A timeout has two possible meanings: the request never reached Volanea, or Volanea received it but the response did not get back to WHMCS in time. That is why immediately retrying with a different idempotency key is unsafe.
The sample sets a five-second connection timeout and a 10-second overall timeout to avoid holding up the WHMCS request indefinitely. If it times out, record the failure without secrets and retry through a controlled process using the same idempotency key. If your account-creation experience cannot tolerate waiting for an external email API, move the send into a durable queue or middleware worker rather than repeatedly extending the synchronous hook timeout.
The key is missing, invalid, or accidentally exposed
A missing environment variable is a server configuration failure. An HTTP authentication response indicates that the key, authorization header, or account access needs review. In both cases, do not fall back to embedding a key in an order-form template or JavaScript just to make testing easier.
If a secret is committed to source control, pasted into a support ticket, included in logs, or exposed to a browser, revoke and replace it. Then update the server-only secret store and restart or reload the relevant PHP runtime as needed.
The sender domain is unverified
Volanea requires a verified sending domain. If the From domain is not verified or does not match an allowed sending identity, the send request can be refused. Resolve that in Volanea rather than changing the sender to a random unrelated mailbox.
Keep the From address static in server-side configuration. A client’s own email should be placed in to or, where appropriate in a different workflow, a reply-to field—not used as the sender identity for a message your business is generating.
Some expected payload fields are missing
Not every client record will have every optional profile field. A client can have an empty company name, no surname, a blank phone number, no custom fields, or preferences that differ based on how the client was created. A hook payload can also vary when records originate through different admin, API, import, or automation paths.
Write mappings defensively. The example uses safe defaults for the greeting, validates the email, and avoids depending on custom fields. If you need a custom field—such as an onboarding plan name—confirm its actual key and presence in your own installation, provide a fallback, and do not send a malformed message when it is absent.
cURL is unavailable or outbound HTTPS is blocked
The sample depends on the PHP cURL extension and the WHMCS server being able to reach api.volanea.com over HTTPS. A locked-down hosting environment may block outbound traffic, have restrictive firewall rules, use an outdated CA bundle, or disable cURL.
Check the server’s PHP extensions and outbound-network policy. If you cannot change those controls, use a server-side middleware service that WHMCS can reach, but keep the middleware authenticated and make its send operation idempotent. Do not try to call Volanea directly from the browser as a workaround.
Extending the pattern beyond welcome email
ClientAdd is a clean first use case, but operational email usually grows beyond welcome messages. WHMCS exposes hook points for billing, orders, services, domains, support, users, and modules. The integration pattern remains consistent: select the event, inspect the documented variables, fetch only the required data if needed, create a focused email, and derive an idempotency key from the specific business event.
Good transactional candidates
Examples that often fit a direct Volanea integration include:
- A paid-invoice receipt after the appropriate invoice payment hook runs.
- A provisioning update after a successful service-module action.
- A service suspension or unsuspension notice.
- A domain registration or transfer completion update.
- An internal alert to staff when a provisioning module fails.
Each needs its own messaging and retry policy. A payment receipt should be based on the settled payment event, not merely an invoice creation. A provisioning email should be based on the successful action hook, not a pending request. Choosing the wrong hook point can produce messages that tell customers something happened before it actually did.
Prefer templates as messages become more complex
Inline HTML is practical for a simple welcome message because the code and content are easy to inspect together. As your email program grows, use versioned, reviewed templates and keep code responsible for supplying trusted variables.
Whether you render HTML in PHP or use a stored Volanea template, escape untrusted customer data before inserting it into HTML. The first name in a client record is not safe HTML merely because it came from your own database; client-facing forms and imports can contain unexpected characters.
Direct hook versus middleware
The direct hook is the simplest architecture when you manage the WHMCS server and can run PHP with cURL and outbound HTTPS. It has fewer moving parts, lower latency, and one place to map the event to the email.
Middleware is useful when you need durable asynchronous queues, central audit controls across several systems, restricted outbound access from the WHMCS server, or advanced enrichment from other services. In that design, the WHMCS hook posts an authenticated event to your middleware, the middleware persists it, and a worker calls Volanea.
Middleware creates responsibilities, not magic. You must authenticate the WHMCS-to-middleware request, validate the payload, protect the Volanea key on the middleware server, store a business-event ID, manage retries, and use that event ID as the idempotency key for Volanea. If those controls are not needed, the direct hook is easier to operate.
Operational checklist
Before enabling this in production, verify the following:
- The hook file is in
/includes/hooks/and is loaded by WHMCS. - The trigger is the documented
ClientAddhook point. - The From address belongs to a domain verified in Volanea.
- The Volanea secret is available only to server-side PHP through an environment variable or protected server configuration.
- No secret, password, address, or full API response is written to logs.
- The recipient comes from
$vars['email']and is checked for a valid email format. - The HTML version escapes dynamic client fields.
- The text version provides a readable fallback.
- The idempotency key is stable for one logical welcome email.
- Your team knows how to inspect the WHMCS activity log and Volanea events when a send fails.
- Test messages go to controlled inboxes before production rollout.
Conclusion
To send email from WHMCS with Volanea, use WHMCS’s native PHP hook system rather than looking for a non-existent marketplace plugin. The ClientAdd hook provides a concrete account-creation trigger and the client fields needed for a safe welcome email; the hook maps those fields into Volanea’s POST /v1/send request from the server.
The parts that make this production-ready are not just the API call. Store the key only on the server, send from a verified domain, minimize the data you transmit, escape content, log narrowly, and use a deterministic idempotency key so retries and repeated WHMCS executions do not become duplicate customer emails.
FAQ
Does Volanea have a native WHMCS plugin?
No. This integration uses a custom WHMCS PHP hook and Volanea’s REST API. You do not need a marketplace installation flow to implement it.
What event sends the email in this guide?
The trigger is WHMCS’s ClientAdd hook point, which executes as a client is added to WHMCS. The hook receives the new client’s variables and sends a welcome email through Volanea.
Where should I store the Volanea API key in WHMCS?
Store it in a server-only environment variable available to PHP, such as VOLANEA_API_KEY. A protected configuration.php constant is a secondary option when environment-secret management is unavailable. Never expose the key in client-side templates, JavaScript, forms, or public endpoints.
How do I stop duplicate welcome emails after a timeout or retry?
Use a stable Idempotency-Key derived from the business event, such as whmcs-client-welcome- plus the WHMCS client_id. Reuse that same key if you retry the same logical email.
Can I use this approach for invoice and provisioning emails?
Yes. Select the appropriate documented WHMCS hook for the completed business event, map only necessary fields, and make the idempotency key specific to that invoice, service action, or notification type.