PHP integration
Send WhatsApp messages with WordPress
A complete, runnable WordPress example for sending WhatsApp messages through the SPWP REST API. There is no SDK to install — WordPress talks to the API over ordinary HTTP, so you can paste this straight into an existing project.
About 5 minutes to your first delivered message
1. Setup
Create an API key in the dashboard under Accounts → your account → API keys, then make it available to your WordPress code as an environment variable. Never commit the key or ship it in client-side code.
# Add the key to wp-config.php rather than hardcoding it in a theme.
define('SPWP_API_KEY', 'wak_live_your_key_here');2. Send a text message
One POST with a recipient and a body. The API replies 202 Accepted with a message id in QUEUED state; delivery happens asynchronously and you can track it by id or webhook.
<?php
// Drop into a small plugin or your theme's functions.php.
function spwp_send_text($to, $text) {
$response = wp_remote_post(
'https://api.spwp.app/api/v1/public/messages/text',
[
'headers' => [
'X-API-Key' => SPWP_API_KEY,
'Content-Type' => 'application/json',
],
'body' => wp_json_encode(['to' => $to, 'text' => $text]),
'timeout' => 15,
]
);
if (is_wp_error($response)) {
error_log('SPWP: ' . $response->get_error_message());
return null;
}
$body = json_decode(wp_remote_retrieve_body($response), true);
return $body['data'] ?? null;
}3. Send an image, document or other media
Media endpoints take the same shape, with a source that is either a public HTTPS URL we fetch server-side or a base64 data URL you upload inline. Swap the path segment for video, audio, document or location.
<?php
// WooCommerce: message the customer when an order is marked complete.
add_action('woocommerce_order_status_completed', function ($order_id) {
$order = wc_get_order($order_id);
$phone = preg_replace('/\D/', '', $order->get_billing_phone());
spwp_send_text(
$phone,
sprintf(
'Thank you! Order #%s has shipped. Total: %s',
$order->get_order_number(),
$order->get_formatted_order_total()
)
);
});4. Receive replies and delivery receipts
Inbound messages and status changes arrive as signed POSTs to your webhook URL. Recompute the HMAC over the timestamp and the raw request body — re-serialised JSON will not match — and reject anything older than five minutes.
<?php
// Register a REST route for inbound WhatsApp messages.
add_action('rest_api_init', function () {
register_rest_route('spwp/v1', '/webhook', [
'methods' => 'POST',
'permission_callback' => '__return_true', // the HMAC is the auth
'callback' => function (WP_REST_Request $request) {
$ts = $request->get_header('X-WA-Timestamp');
preg_match('/v1=([a-f0-9]+)/', (string) $request->get_header('X-WA-Signature'), $m);
$v1 = $m[1] ?? '';
$body = $request->get_body();
$expected = hash_hmac('sha256', "$ts.$body", SPWP_WEBHOOK_SECRET);
if (!$ts || !$v1 || !hash_equals($expected, $v1)) {
return new WP_REST_Response(null, 401);
}
$event = json_decode($body, true);
// …handle $event['data']…
return new WP_REST_Response(null, 200);
},
]);
});Error handling
Errors carry a non-2xx status and a stable code string you can branch on: VALIDATION_FAILED, INVALID_API_KEY, ACCOUNT_NOT_CONNECTED, RATE_LIMITED, MEDIA_FETCH_FAILED. Retry on 429 while honouring Retry-After; treat 401 as a configuration problem rather than a transient one.
Next steps
The full reference covers every endpoint, field and error code, plus the webhook payload shapes.