Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
98a0d58
Add feature: add support for creating and updating WhatsApp message t…
krishna035 May 19, 2025
c9b3560
Refactor Client class and improve ResponseException handling
krishna035 May 30, 2025
d5d850e
remove empty line before closing brace in Client class
krishna035 May 30, 2025
52b93f4
Added PHPUnit tests for the new methods
krishna035 Jun 10, 2025
a48bf24
Support empty profile name on Notification
rafaelqueiroz Dec 9, 2025
b7b8c3b
Add support for frequently forwarded messages in context
aleedhillon Feb 12, 2025
8d3631c
Apply suggestions from code review
aalbarca Feb 27, 2026
35989ba
Remove php7.4 support
aalbarca Feb 27, 2026
8831aa6
Test "frequently_forwarded" field
aalbarca Feb 27, 2026
36db11d
feat: Add type property to Media Class
Yi-pixel Feb 26, 2025
6356284
MessageNotificationFactory now is a final class
aalbarca Feb 27, 2026
a3ebd59
Changed order for MediaType constructor parameter
aalbarca Feb 27, 2026
50b6a96
Merge pull request #234 from rafaelqueiroz/hotfix/contact-without-pro…
aalbarca Feb 27, 2026
0b1d5b0
Test webhook notification without user profile
aalbarca Feb 27, 2026
90e1bfd
Update Github workflow to remove php7.4 support
aalbarca Feb 27, 2026
ebf5cd6
Fix webhook tests to php8.3 compatibility
aalbarca Feb 27, 2026
128c123
Support new phpunit versions
aalbarca Feb 27, 2026
167864f
Update phpunit.xml to new v12 schema
aalbarca Feb 27, 2026
8f8936f
Remove support for php8.0v
aalbarca Feb 27, 2026
f04e42b
Merge pull request #227 from krishna035/feature/create-update-template
aalbarca Feb 27, 2026
22b5364
Initial plan
Copilot Mar 6, 2026
3e6f9d5
Update UPGRADE.md with 2.x to 3.x migration instructions
Copilot Mar 6, 2026
f502472
Merge pull request #240 from netflie/copilot/update-upgrade-md-instru…
aalbarca Mar 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/php.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
strategy:
fail-fast: true
matrix:
php: [7.4, 8.0, 8.1]
php: [8.1, 8.2, 8.3, 8.4]

name: Tests on PHP ${{ matrix.php }} - ${{ matrix.stability }}

Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ composer.phar
.phpunit.result.cache
composer.lock
.php-cs-fixer.cache
.idea/
.idea/
.phpunit.cache
108 changes: 108 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,112 @@ $whatsapp_cloud_api->updateBusinessProfile([
]);
```

### Create a Template
```php
<?php

$whatsapp = new WhatsAppCloudApi([
'from_phone_number_id' => 'your-configured-from-phone-number-id',
'access_token' => 'your-facebook-whatsapp-application-token',
'business_id' => 'your-business-id',
]);

$whatsapp->createTemplate(
'seasonal_promotion',
'MARKETING', // UTILITY | MARKETING | AUTHENTICATION
'en_US',
[
[
'type' => 'HEADER',
'format' => 'TEXT',
'text' => 'Our {{1}} is on!',
'example' => [
'header_text' => ['Summer Sale']
]
],
[
'type' => 'BODY',
'text' => 'Shop now through {{1}} and use code {{2}} to get {{3}} off of all merchandise.',
'example' => [
'body_text' => [[ 'the end of August', '25OFF', '25%' ]]
]
],
[
'type' => 'FOOTER',
'text' => 'Use the buttons below to manage your marketing subscriptions'
],
[
'type' => 'BUTTONS',
'buttons' => [
[
'type' => 'QUICK_REPLY',
'text' => 'Unsubscribe from Promos'
],
[
'type' => 'QUICK_REPLY',
'text' => 'Unsubscribe from All'
]
]
]
]
);
```

### Update a Template
```php
<?php

$whatsapp = new WhatsAppCloudApi([
'from_phone_number_id' => 'your-configured-from-phone-number-id',
'access_token' => 'your-facebook-whatsapp-application-token',
'business_id' => 'your-business-id',
]);

$template_id = 'your-template-id';

// New payload to update the template
$payload = [
'category' => 'MARKETING',
'language' => 'en_US',
'components' => [
[
'type' => 'HEADER',
'format' => 'TEXT',
'text' => 'Hello {{1}} is live now!',
'example' => [
'header_text' => ['Flash Sale']
]
],
[
'type' => 'BODY',
'text' => 'Buy now before {{1}} ends. Use code {{2}} to get {{3}} off!',
'example' => [
'body_text' => [['midnight', 'FLASH20', '20%']]
]
],
[
'type' => 'FOOTER',
'text' => 'Tap below to shop.'
],
[
'type' => 'BUTTONS',
'buttons' => [
[
'type' => 'QUICK_REPLY',
'text' => 'Show Me Deals'
],
[
'type' => 'QUICK_REPLY',
'text' => 'Stop Promotions'
]
]
]
]
];

$whatsapp->updateTemplateById($template_id, $payload);
```

Fields list: https://developers.facebook.com/docs/whatsapp/cloud-api/reference/business-profiles

## Features
Expand All @@ -528,6 +634,8 @@ Fields list: https://developers.facebook.com/docs/whatsapp/cloud-api/reference/b
- Get/Update Business Profile
- Webhook verification
- Webhook notifications
- Create Template
- Update Template

## Getting Help
- Ask a question on the [Discussions forum](https://github.com/netflie/whatsapp-cloud-api/discussions "Discussions forum")
Expand Down
127 changes: 126 additions & 1 deletion UPGRADE.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,132 @@
# Upgrade to v2
# Upgrade Guide

All instructions to upgrade this project from one major version to the next will be documented in this file. Upgrades must be run sequentially, meaning you should not skip major releases while upgrading (fix releases can be skipped).

## 2.x to 3.x

### PHP version requirement

PHP 7.4 and PHP 8.0 are no longer supported. The minimum required PHP version is now **PHP 8.1**. Update your environment accordingly before upgrading.

### `MessageNotificationFactory` is now `final`

`Netflie\WhatsAppCloudApi\WebHook\Notification\MessageNotificationFactory` has been marked as `final`. If you have extended this class, you must refactor your code to use composition instead of inheritance.

### `Media` constructor signature changed

A new required `MediaType $type` parameter has been added to the `Media` constructor. If you are instantiating `Netflie\WhatsAppCloudApi\WebHook\Notification\Media` directly, you must pass a `Netflie\WhatsAppCloudApi\Message\Media\MediaType` instance as the eighth argument (before `$received_at_timestamp`).

Before:
```php
new Media($id, $business, $image_id, $mime_type, $sha256, $filename, $caption, $received_at_timestamp);
```

After:
```php
use Netflie\WhatsAppCloudApi\Message\Media\MediaType;

new Media($id, $business, $image_id, $mime_type, $sha256, $filename, $caption, new MediaType('image'), $received_at_timestamp);
```

### `Context` constructor signature changed

A new `bool $frequently_forwarded` parameter has been added to the `Context` constructor between `$forwarded` and `$referred_product`. If you are instantiating `Netflie\WhatsAppCloudApi\WebHook\Notification\Support\Context` directly, update your call accordingly.

Before:
```php
new Context($replying_to_message_id, $forwarded, $referred_product);
```

After:
```php
new Context($replying_to_message_id, $forwarded, $frequently_forwarded, $referred_product);
```

### `Referral` constructor signature changed

A new required `string $ctwa_clid` parameter has been appended to the `Referral` constructor. If you are instantiating `Netflie\WhatsAppCloudApi\WebHook\Notification\Support\Referral` directly, pass the Click to WhatsApp click ID as the last argument.

Before:
```php
new Referral($source_id, $source_url, $source_type, $headline, $body, $media_type, $media_url, $thumbnail_url);
```

After:
```php
new Referral($source_id, $source_url, $source_type, $headline, $body, $media_type, $media_url, $thumbnail_url, $ctwa_clid);
```

### New features

The following new features are available in 3.x:

#### Send Single Product Message

```php
$whatsapp_cloud_api->sendSingleProduct(
'<destination-phone-number>',
'<catalog-id>',
'<product-sku-id>',
'Optional body text',
'Optional footer text'
);
```

#### Create and Update Templates

Template management now requires a `business_id` in the `WhatsAppCloudApi` constructor:

```php
$whatsapp = new WhatsAppCloudApi([
'from_phone_number_id' => 'your-phone-number-id',
'access_token' => 'your-access-token',
'business_id' => 'your-business-id',
]);

// Create a template
$whatsapp->createTemplate('template_name', 'MARKETING', 'en_US', $components);

// Update a template by ID
$whatsapp->updateTemplateById('<template-id>', $payload);
```

#### Frequently forwarded messages

`MessageNotification` and `Context` now expose an `isFrequentlyForwarded()` method:

```php
$notification->isFrequentlyForwarded();
$notification->context()->isFrequentlyForwarded();
```

#### Media type in Webhook notifications

`Media` notifications now expose the media type via `type()`, which returns a `MediaType` enum value:

```php
$notification->type(); // returns a MediaType enum instance
```

#### Click to WhatsApp click ID in Referral

`Referral` now exposes the `ctwaClid()` method:

```php
$notification->referral()->ctwaClid();
```

#### `VerificationRequest` response code

`VerificationRequest::verify()` no longer calls `http_response_code()` when headers have already been sent. You can now read the resulting HTTP status code via the new `responseCode()` method:

```php
$verificationRequest = new VerificationRequest($verify_token);
$challenge = $verificationRequest->verify($payload);
$code = $verificationRequest->responseCode(); // 200 or 403
```

---

## 1.x to 2.x

# Final classes
Expand Down
8 changes: 4 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@
],
"license": "MIT",
"require": {
"php": "^7.4 || ^8.0 || ^8.1",
"php": ">=8.1",
"guzzlehttp/guzzle": "^7.0",
"vlucas/phpdotenv": "^5.4",
"myclabs/php-enum": "^1.8"
},
"require-dev": {
"phpunit/phpunit": "^9.0",
"phpunit/phpunit": ">=10.0",
"symfony/var-dumper": "^5.0",
"phpspec/prophecy-phpunit": "^2.0",
"fakerphp/faker": "^1.19",
Expand All @@ -38,7 +38,7 @@
}
},
"scripts": {
"unit-test": "vendor/bin/phpunit --group unit",
"integration-test": "vendor/bin/phpunit --group integration"
"unit-test": "vendor/bin/phpunit --testsuite unit",
"integration-test": "vendor/bin/phpunit --testsuite integration"
}
}
14 changes: 7 additions & 7 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="vendor/autoload.php" backupGlobals="false" backupStaticAttributes="false" colors="true" verbose="true" convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
<coverage>
<include>
<directory suffix=".php">src/</directory>
</include>
</coverage>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="vendor/autoload.php" backupGlobals="false" colors="true" processIsolation="false" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/12.5/phpunit.xsd" cacheDirectory=".phpunit.cache" backupStaticProperties="false">
<testsuites>
<testsuite name="unit">
<directory>tests/Unit</directory>
Expand All @@ -16,4 +11,9 @@
<php>
<env name="CACHE_DRIVER" value="array"/>
</php>
</phpunit>
<source>
<include>
<directory suffix=".php">src/</directory>
</include>
</source>
</phpunit>
44 changes: 44 additions & 0 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

use Netflie\WhatsAppCloudApi\Http\ClientHandler;
use Netflie\WhatsAppCloudApi\Http\GuzzleClientHandler;
use Netflie\WhatsAppCloudApi\Request\TemplateRequest\CreateTemplateRequest;
use Netflie\WhatsAppCloudApi\Request\TemplateRequest\UpdateTemplateRequest;

class Client
{
Expand Down Expand Up @@ -191,4 +193,46 @@ private function buildRequestUri(string $node_path): string
{
return $this->buildBaseUri() . '/' . $node_path;
}

/**
* Handles sending a template request (create/update) and processing the response.
*
* @param object $request The request object with required methods.
*
* @return Response
*
* @throws \Netflie\WhatsAppCloudApi\Response\ResponseException
*/
private function sendTemplateRequest($request): Response
{
$raw_response = $this->handler->postJsonData(
$this->buildRequestUri($request->nodePath()),
$request->body(),
$request->headers(),
$request->timeout()
);

$return_response = new Response(
$request,
$raw_response->body(),
$raw_response->httpResponseCode(),
$raw_response->headers()
);

if ($return_response->isError()) {
$return_response->throwException();
}

return $return_response;
}

public function createTemplate(CreateTemplateRequest $request): Response
{
return $this->sendTemplateRequest($request);
}

public function updateTemplate(UpdateTemplateRequest $request): Response
{
return $this->sendTemplateRequest($request);
}
}
Loading