Send WhatsApp messages with PHP
Plain PHP with the cURL extension is all you need β it works the same in Laravel, CodeIgniter, WordPress plugins and WooCommerce hooks.
Before you start
- Create a free account and copy your API key from Settings.
- Add a WhatsApp number and scan the QR code; copy its instance id.
- Replace
YOUR_API_KEYandYOUR_INSTANCE_IDin the examples below.
1. Setup
# PHP 7.4+ with the curl extension
2. Send a WhatsApp text message with PHP
The recipient goes in to with the country code (for India, 91 followed by the 10-digit number). The response contains the message id and status.
<?php
$apiKey = "YOUR_API_KEY";
$instanceId = "YOUR_INSTANCE_ID";
$base = "https://powerapiwa.com/api/v1";
$ch = curl_init("$base/instances/$instanceId/send");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["x-api-key: $apiKey", "Content-Type: application/json"],
CURLOPT_POSTFIELDS => json_encode([
"to" => "919876543210",
"type" => "text",
"message" => "Hello from PHP π",
]),
]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);
echo $data["message"]["status"]; // sent
3. Send an image, PDF or location
Change the type: media_url for files from a URL, media for base64 uploads, location, poll or contact.
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
"to" => "919876543210",
"type" => "media_url",
"url" => "https://example.com/invoice.pdf",
"caption" => "Your invoice",
]));
4. Receive messages with a webhook
Set your endpoint URL on the WhatsApp number in the dashboard. Always verify the X-PowerAPI-Signature header before trusting the payload.
<?php
$secret = "YOUR_WEBHOOK_SECRET";
$body = file_get_contents("php://input");
$expected = hash_hmac("sha256", $body, $secret);
if (!hash_equals($expected, $_SERVER["HTTP_X_POWERAPI_SIGNATURE"] ?? "")) {
http_response_code(401);
exit;
}
$event = json_decode($body, true);
if ($event["event"] === "message") {
error_log($event["data"]["message"]["from"] . ": " . ($event["data"]["message"]["body"] ?? ""));
}
echo json_encode(["ok" => true]);
Response and errors
Successful calls return {"success": true, ...}. Errors return {"success": false, "error": "..."} with a status code: 401 invalid key, 402 plan expired, 422 invalid payload, 429 daily limit reached. See the full API documentation.