SDK setup and examples
Install and use the TypeScript, Python, and PHP clients from a backend service.
Environment variables
All SDK examples assume your backend has a base URL, API key, and sender ID configured as environment variables.
`HOOKMESSAGE_BASE_URL` is the backend API origin, not the frontend dashboard origin. `HOOKMESSAGE_API_KEY` must be created from the dashboard and kept server-side.
HOOKMESSAGE_BASE_URL=https://your-api-domain.com
HOOKMESSAGE_API_KEY=was_xxx
HOOKMESSAGE_SENDER_ID=9f4b5d4c-0000-4000-9000-123456789abcTypeScript client
The TypeScript client lives in `src/sdk/wa-sender-client.ts` and is exposed by the local package metadata in `sdk/typescript/package.json`.
Use it only from a server route, worker, or backend service. The client sends `x-api-key`, normalizes the base URL, applies a timeout, and throws `WaApiError` on non-2xx responses.
import { WaApiError, WaSenderClient } from "@whsender/client";
const wa = new WaSenderClient({
baseUrl: process.env.HOOKMESSAGE_BASE_URL!,
apiKey: process.env.HOOKMESSAGE_API_KEY!,
timeoutMs: 15000,
});
export async function sendOrderConfirmation(phone: string, orderId: string) {
try {
return await wa.sendMessage({
senderId: process.env.HOOKMESSAGE_SENDER_ID!,
receiverNumber: phone,
message: `Your order ${orderId} is confirmed.`,
sourceSystem: "checkout",
sourceReference: orderId,
idempotencyKey: `order:${orderId}:confirmed`,
});
} catch (error) {
if (error instanceof WaApiError) {
console.error(error.statusCode, error.code, error.body);
}
throw error;
}
}Python client
The Python client lives in `sdk/python/wa_sender_client.py` and depends on `requests` from `sdk/python/requirements.txt`.
Use the client from backend code, cron jobs, or queue workers. It raises `WaApiError` with `status_code` and `body` when the API rejects a request.
import os
from wa_sender_client import WaApiError, WaSenderClient
wa = WaSenderClient(
base_url=os.environ["HOOKMESSAGE_BASE_URL"],
api_key=os.environ["HOOKMESSAGE_API_KEY"],
timeout=20.0,
)
def send_login_otp(phone: str) -> dict:
try:
return wa.send_otp(
sender_id=os.environ["HOOKMESSAGE_SENDER_ID"],
receiver_number=phone,
app_name="My Store",
ttl_minutes=10,
source_system="login",
idempotency_key=f"login:{phone}",
)
except WaApiError as exc:
print(exc.status_code, exc.body)
raisePHP client
The PHP client lives in `sdk/php/src` and uses Composer PSR-4 autoloading from `sdk/php/composer.json`.
Use it from Laravel services, Symfony services, plain PHP jobs, or any backend process. It throws `WaApiException` with `statusCode()` and `body()` for API errors.
use WhSender\WaApiException;
use WhSender\WaSenderClient;
$wa = new WaSenderClient(
getenv('HOOKMESSAGE_BASE_URL'),
getenv('HOOKMESSAGE_API_KEY'),
15,
);
try {
$message = $wa->sendMessage([
'senderId' => getenv('HOOKMESSAGE_SENDER_ID'),
'receiverNumber' => $customerPhone,
'message' => 'Your appointment is confirmed.',
'sourceSystem' => 'appointments',
'sourceReference' => (string) $appointmentId,
'idempotencyKey' => "appointment:{$appointmentId}:confirmed",
]);
} catch (WaApiException $exception) {
error_log(json_encode($exception->body()));
throw $exception;
}PHP Composer path install
Until the PHP SDK is published to a registry, install it as a local Composer path repository or copy the `WhSender` namespace into your backend.
The package name from `sdk/php/composer.json` is `whsender/wa-sender-client`.
composer config repositories.whsender path ../sdk/php
composer require whsender/wa-sender-client:*SDK method list
Use these supported SDK methods as the stable integration surface. If your use case needs a route not listed here, call the REST API directly or generate a client from OpenAPI.
SDK health and status checks
Before enabling production sends, call `listSenders()` and confirm the sender you configured is returned with `status: connected`.
After a send response, store `message_id`. Use `getMessageStatus(message_id)` when your product needs to display delivery state or diagnose a failed delivery.
const senders = await wa.listSenders();
const sender = senders.find((item) => item.sender_id === process.env.HOOKMESSAGE_SENDER_ID);
if (!sender || sender.status !== "connected") {
throw new Error("Configured sender is not connected or not assigned to this API key.");
}
const queued = await wa.sendMessage({
senderId: sender.sender_id,
receiverNumber: "212612345678",
message: "Test message",
idempotencyKey: "test-message-001",
});
const status = await wa.getMessageStatus(queued.message_id);Need help?
Use Book Integration Help if you want setup help for OTP or automated customer messaging.
Next steps
Quickstart
A practical path from empty workspace to a working server-side integration.
Authentication and access
HookMessage separates customer API keys, dashboard sessions, and internal platform access.
Workspaces
A workspace is the tenant boundary for every customer resource.
Senders and sessions
A sender is the WhatsApp number used to deliver messages for a workspace.