How to Send WhatsApp Messages from PHP (No Composer Required)
Send WhatsApp messages from PHP using plain cURL — no dependency required. Session setup, QR auth, sending text/images/files, and production error handling.
Meta Description: Send WhatsApp messages from PHP with plain cURL — no Composer dependency required. Complete guide: session setup, QR auth, sending text/images/files, and production error handling.
Introduction
Most "WhatsApp API PHP" tutorials start with composer require and a wrapper library. You don't need one. The WhatsApp Messaging API is plain REST over HTTPS, so PHP's built-in cURL functions are enough to send your first message.
In this guide, you'll send a real WhatsApp message from PHP in under 5 minutes, then extend that into a small helper class you can drop into any codebase — vanilla PHP, WordPress, or Laravel.
What you'll need:
- •PHP 7.4+ with the
curlextension (enabled by default on almost every host) - •A RapidAPI account (free)
- •5 minutes
Let's send a message.
Step 1: Get Your API Key (30 seconds)
- 1.Go to RapidAPI Hub
- 2.Search for "Whatsapp messaging bot"
- 3.Click Subscribe (Free plan available, no card required)
- 4.Open API Settings and copy your X-RapidAPI-Key
That key authenticates every request below.
Step 2: Create a WhatsApp Session
Before sending a message, pair a session — this is the WhatsApp account the API sends on behalf of.
<?php
// session.php
$apiKey = getenv('RAPIDAPI_KEY');
$apiHost = 'whatsapp-messaging-bot.p.rapidapi.com';
$baseUrl = "https://$apiHost";
$sessionName = 'my-session';
function callApi(string $method, string $path, ?array $body = null): array {
global $apiKey, $apiHost, $baseUrl;
$ch = curl_init("$baseUrl$path");
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"x-rapidapi-key: $apiKey",
"x-rapidapi-host: $apiHost",
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => $body ? json_encode($body) : null,
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return ['status' => $status, 'body' => json_decode($response, true)];
}
// Create the session
$result = callApi('POST', '/v1/sessions', ['name' => $sessionName]);
echo "Session created: " . json_encode($result['body']) . "\n";
// Get the QR code to authenticate
$qr = callApi('GET', "/v1/sessions/$sessionName/auth/qr");
echo "Scan this QR with WhatsApp → Linked Devices:\n";
echo $qr['body']['qr'] ?? 'QR not ready yet, retry in a second';Run it:
RAPIDAPI_KEY=your_key_here php session.phpOpen WhatsApp on your phone → Settings → Linked Devices → Link a Device, and scan the printed QR code.
Step 3: Send Your First Message
Once the session shows as authenticated, sending is a single request:
<?php
// send.php
require 'session.php'; // reuses callApi() and $sessionName above
function sendWhatsAppMessage(string $chatId, string $text): array {
global $sessionName;
return callApi('POST', '/v1/sendText', [
'chatId' => $chatId, // just the number: "14155552671"
'text' => $text,
'session' => $sessionName,
]);
}
$result = sendWhatsAppMessage('14155552671', 'Hello from PHP!');
if ($result['status'] === 200 || $result['status'] === 201) {
echo "Message sent.\n";
} else {
echo "Send failed: " . json_encode($result['body']) . "\n";
}php send.phpCheck your phone. That's a real WhatsApp message sent from PHP with zero dependencies.
Step 4: Sending Images, Files, and Voice Notes
Same callApi() helper, different endpoint:
function sendImage(string $chatId, string $imageUrl, string $caption = ''): array {
global $sessionName;
return callApi('POST', '/v1/sendImage', [
'chatId' => $chatId,
'image' => $imageUrl,
'caption' => $caption,
'session' => $sessionName,
]);
}
function sendFile(string $chatId, string $fileUrl, string $filename): array {
global $sessionName;
return callApi('POST', '/v1/sendFile', [
'chatId' => $chatId,
'file' => $fileUrl,
'filename' => $filename,
'session' => $sessionName,
]);
}Both take a public URL — no need to upload the file yourself first. Full parameter reference for every message type (including voice, video, location, and contact cards) is in the interactive API reference.
Production Best Practices
1. Retry with backoff
A single failed request shouldn't fail the whole job. Wrap sends in a retry loop:
function sendWithRetry(string $chatId, string $text, int $maxRetries = 3): array {
for ($attempt = 1; $attempt <= $maxRetries; $attempt++) {
$result = sendWhatsAppMessage($chatId, $text);
if ($result['status'] < 400) {
return $result;
}
sleep($attempt * 2); // 2s, 4s, 6s backoff
}
return $result;
}2. Don't recreate sessions per request
A session is a persistent, authenticated connection — create it once, store the session name (in your .env, a config table, wherever your app already keeps settings), and reuse it across every subsequent request. Recreating it per request just adds latency for nothing.
3. Confirm delivery with a webhook, not the HTTP response
A 200 from /v1/sendText means "accepted," not "delivered" — a number that isn't on WhatsApp can still return success. Register a webhook and read the message.ack event for real delivery/read status:
callApi('POST', "/v1/sessions/$sessionName/webhooks", [
'webhookUrl' => 'https://yourapp.com/webhooks/whatsapp',
'events' => ['message.ack'],
]);Troubleshooting
| Issue | Fix |
|---|---|
| 401 Unauthorized | Your RAPIDAPI_KEY env var isn't set, or the key's been rotated in the RapidAPI dashboard. |
| cURL error 60 (SSL) | Older PHP builds ship an outdated CA bundle — update curl.cainfo in php.ini or your host's cURL package. |
| QR code expires before you scan it | QR codes are short-lived. Fetch it right before you're ready to scan, not minutes ahead. |
| Message accepted but never arrives | Check message.ack via webhook — a 200 only means the API accepted the send, not that WhatsApp delivered it. |
Next Steps
- •WhatsApp OTP Authentication — use this same PHP setup to send login codes instead of SMS
- •Send Files, PDFs, and Documents via WhatsApp API — full MIME type reference and size limits
- •Best WhatsApp API for Startups and Indie Hackers — how this compares on price and setup time
- •Will My Number Get Banned? — the honest version of the "unofficial libraries get you banned" warning you'll see elsewhere
External references:
- •PHP cURL documentation — every function used in this guide
- •WhatsApp Business Platform overview — Meta's official docs, for context on how the official API differs
Try Free on RapidAPI → Get your API key in 30 seconds → Send your first PHP message in 5 minutes.
Ready to Get Started?
Try the WhatsApp API free on RapidAPI with no credit card required.
Try Free on RapidAPI