renzojohnson / whatsapp-cloud-api
Lightweight PHP wrapper for Meta's WhatsApp Cloud API. Send text, template, image, document, video, audio, location, contact, and sticker messages. Receive webhooks with signature verification. Zero dependencies.
Installs: 0
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/renzojohnson/whatsapp-cloud-api
Requires
- php: ^8.4
- ext-curl: *
- ext-json: *
Requires (Dev)
- phpunit/phpunit: ^11.0
README
Lightweight PHP wrapper for Meta's WhatsApp Cloud API. Zero dependencies.
Send text, template, image, document, video, audio, location, contact, and sticker messages. Receive and verify webhooks.
Author: Renzo Johnson
Requirements
- PHP 8.4+
- ext-curl
- ext-json
Installation
composer require renzojohnson/whatsapp-cloud-api
Quick Start
use RenzoJohnson\WhatsApp\WhatsApp; $wa = new WhatsApp('YOUR_PHONE_NUMBER_ID', 'YOUR_ACCESS_TOKEN'); // Send a text message $wa->sendText('14155551234', 'Hello from PHP!');
Sending Messages
Text
$wa->sendText('14155551234', 'Hello World'); // With link preview $wa->sendText('14155551234', 'Check https://example.com', previewUrl: true);
Template
// Simple template (no parameters) $wa->sendTemplate('14155551234', 'hello_world', 'en_US'); // Template with parameters $wa->sendTemplate('14155551234', 'order_update', 'en_US', [ [ 'type' => 'body', 'parameters' => [ ['type' => 'text', 'text' => 'John'], ['type' => 'text', 'text' => 'ORD-12345'], ], ], ]);
Image
// By URL $wa->sendImage('14155551234', link: 'https://example.com/photo.jpg', caption: 'A photo'); // By media ID (uploaded via uploadMedia) $wa->sendImage('14155551234', mediaId: 'media_123');
Document
$wa->sendDocument( '14155551234', link: 'https://example.com/invoice.pdf', caption: 'Your invoice', filename: 'invoice-2026.pdf', );
Video
$wa->sendVideo('14155551234', link: 'https://example.com/clip.mp4', caption: 'Watch this');
Audio
$wa->sendAudio('14155551234', link: 'https://example.com/audio.mp3');
Location
$wa->sendLocation( '14155551234', latitude: 28.5383, longitude: -81.3792, name: 'Orlando Office', address: '123 Main St, Orlando, FL', );
Contact
$wa->sendContact( '14155551234', name: ['first_name' => 'Jane', 'last_name' => 'Doe'], phones: [['phone' => '+14155559999', 'type' => 'CELL']], );
Sticker
$wa->sendSticker('14155551234', link: 'https://example.com/sticker.webp');
Media
Upload
$response = $wa->uploadMedia('/path/to/file.jpg', 'image/jpeg'); $mediaId = $response['id'];
Get Media URL
$media = $wa->getMedia('media_123'); $url = $media['url'];
Delete
$wa->deleteMedia('media_123');
Mark as Read
$wa->markAsRead('wamid.abc123');
Webhooks
Verification (GET request from Meta)
use RenzoJohnson\WhatsApp\Webhook\Listener; // Responds to Meta's verification challenge Listener::verify('YOUR_VERIFY_TOKEN');
Receiving Messages (POST from Meta)
use RenzoJohnson\WhatsApp\Webhook\Listener; use RenzoJohnson\WhatsApp\Webhook\Notification; Listener::listen('YOUR_APP_SECRET', function (Notification $notification, array $raw) { if ($notification->isText()) { echo 'From: ' . $notification->from . "\n"; echo 'Text: ' . $notification->text . "\n"; } if ($notification->isImage()) { echo 'Image ID: ' . $notification->image['id'] . "\n"; } });
The listener validates the X-Hub-Signature-256 header using HMAC-SHA256 before processing. Invalid signatures return 401.
Notification Properties
| Property | Type | Description |
|---|---|---|
from |
string | Sender's phone number |
type |
string | Message type (text, image, document, etc.) |
timestamp |
string | Unix timestamp |
messageId |
?string | WhatsApp message ID |
text |
?string | Text body (when type is text) |
image |
?array | Image data (id, mime_type, sha256) |
document |
?array | Document data |
video |
?array | Video data |
audio |
?array | Audio data |
location |
?array | Location data (latitude, longitude) |
sticker |
?array | Sticker data |
contacts |
?array | Contact cards |
interactive |
?array | Interactive response data |
context |
?array | Reply context (quoted message) |
Type Checks
$notification->isText(); $notification->isImage(); $notification->isDocument(); $notification->isVideo(); $notification->isAudio(); $notification->isLocation(); $notification->isSticker(); $notification->isInteractive();
Error Handling
use RenzoJohnson\WhatsApp\Exception\AuthenticationException; use RenzoJohnson\WhatsApp\Exception\RateLimitException; use RenzoJohnson\WhatsApp\Exception\WhatsAppException; try { $wa->sendText('14155551234', 'Hello'); } catch (AuthenticationException $e) { // Invalid or expired access token (401) } catch (RateLimitException $e) { // Too many requests (429) } catch (WhatsAppException $e) { // Other API errors (400, 500, etc.) $errorData = $e->getErrorData(); }
Testing
composer install vendor/bin/phpunit
Links
License
MIT License. Copyright (c) 2026 Renzo Johnson.