All integration guides

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.

Other languages and frameworks