Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
35.29% covered (danger)
35.29%
6 / 17
60.00% covered (warning)
60.00%
3 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
WhatsAppCloudChannel
35.29% covered (danger)
35.29%
6 / 17
60.00% covered (warning)
60.00%
3 / 5
20.27
0.00% covered (danger)
0.00%
0 / 1
 key
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 label
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 configSchema
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 send
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
 isImplemented
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace App\Services\Notification\Channels;
4
5use App\Services\Notification\Contracts\NotificationChannelContract;
6use Illuminate\Support\Facades\Http;
7
8/**
9 * WhatsApp Cloud API (Meta) — https://developers.facebook.com/docs/whatsapp/cloud-api.
10 * Sends a plain text message. Note a real Cloud API constraint this doesn't
11 * work around: Meta only allows free-form text within the 24-hour customer
12 * service window after the customer last messaged the business; outside
13 * that window a message must use a pre-approved template instead, or the
14 * API rejects it — template messages are a separate, larger feature not
15 * built here.
16 */
17class WhatsAppCloudChannel implements NotificationChannelContract
18{
19    public function key(): string
20    {
21        return 'whatsapp';
22    }
23
24    public function label(): string
25    {
26        return 'WhatsApp';
27    }
28
29    public function configSchema(): array
30    {
31        return [
32            'phone_number_id' => ['type' => 'text', 'label' => 'Phone Number ID', 'required' => true],
33            'access_token' => ['type' => 'password', 'label' => 'Permanent Access Token', 'required' => true],
34        ];
35    }
36
37    public function send(string $to, string $subject, string $body, array $config): array
38    {
39        if (empty($config['phone_number_id']) || empty($config['access_token'])) {
40            return ['ok' => false, 'response' => 'WhatsApp is not configured.'];
41        }
42
43        $response = Http::withToken($config['access_token'])
44            ->post("https://graph.facebook.com/v19.0/{$config['phone_number_id']}/messages", [
45                'messaging_product' => 'whatsapp',
46                'to' => $to,
47                'type' => 'text',
48                'text' => ['body' => $body],
49            ]);
50
51        return ['ok' => $response->successful(), 'response' => $response->body()];
52    }
53
54    public function isImplemented(): bool
55    {
56        return true;
57    }
58}