whatsapp-cloud 0.0.4 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/agent_docs/INCOMING_MESSAGES_BRAINSTORM.md +500 -0
  3. package/cloud-api-docs/webhooks/endpoint.md +112 -0
  4. package/cloud-api-docs/webhooks/overview.md +154 -0
  5. package/docs/DEVELOPMENT.md +154 -0
  6. package/docs/webhooks.md +76 -0
  7. package/package.json +6 -2
  8. package/src/client/HttpClient.ts +43 -6
  9. package/src/client/WhatsAppClient.ts +6 -0
  10. package/src/examples/main.ts +9 -0
  11. package/src/examples/template.ts +134 -0
  12. package/src/index.ts +7 -0
  13. package/src/schemas/client.ts +2 -2
  14. package/src/schemas/index.ts +2 -0
  15. package/src/schemas/templates/component.ts +145 -0
  16. package/src/schemas/templates/index.ts +4 -0
  17. package/src/schemas/templates/request.ts +78 -0
  18. package/src/schemas/templates/response.ts +64 -0
  19. package/src/schemas/webhooks/incoming-message.ts +38 -0
  20. package/src/schemas/webhooks/index.ts +3 -0
  21. package/src/schemas/webhooks/payload.ts +56 -0
  22. package/src/services/accounts/AccountsClient.ts +6 -14
  23. package/src/services/accounts/AccountsService.ts +19 -21
  24. package/src/services/accounts/methods/list-phone-numbers.ts +1 -2
  25. package/src/services/business/BusinessClient.ts +1 -9
  26. package/src/services/business/BusinessService.ts +19 -21
  27. package/src/services/business/methods/list-accounts.ts +1 -2
  28. package/src/services/messages/MessagesClient.ts +2 -6
  29. package/src/services/messages/MessagesService.ts +42 -22
  30. package/src/services/templates/TemplatesClient.ts +35 -0
  31. package/src/services/templates/TemplatesService.ts +117 -0
  32. package/src/services/templates/index.ts +3 -0
  33. package/src/services/templates/methods/create.ts +27 -0
  34. package/src/services/templates/methods/delete.ts +38 -0
  35. package/src/services/templates/methods/get.ts +23 -0
  36. package/src/services/templates/methods/list.ts +36 -0
  37. package/src/services/templates/methods/update.ts +35 -0
  38. package/src/services/webhooks/WebhooksService.ts +214 -0
  39. package/src/services/webhooks/index.ts +3 -0
  40. package/src/services/webhooks/utils/extract-messages.ts +25 -0
  41. package/src/services/webhooks/utils/extract-statuses.ts +25 -0
  42. package/src/services/webhooks/utils/verify.ts +29 -0
  43. package/src/types/index.ts +2 -0
  44. package/src/types/templates/component.ts +33 -0
  45. package/src/types/templates/index.ts +4 -0
  46. package/src/types/templates/request.ts +28 -0
  47. package/src/types/templates/response.ts +34 -0
  48. package/src/types/webhooks/incoming-message.ts +16 -0
  49. package/src/types/webhooks/index.ts +3 -0
  50. package/src/types/webhooks/payload.ts +8 -0
  51. package/tsconfig.json +2 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # whatzapp
2
2
 
3
+ ## 0.0.6
4
+
5
+ ### Patch Changes
6
+
7
+ - a46c084: export types
8
+ - 175d774: add webhooks namespace
9
+
10
+ ## 0.0.5
11
+
12
+ ### Patch Changes
13
+
14
+ - baf823b: added templates namespace
15
+
3
16
  ## 0.0.4
4
17
 
5
18
  ### Patch Changes
@@ -0,0 +1,500 @@
1
+ # Incoming Messages & Webhooks - Brainstorming Document
2
+
3
+ ## 🎯 Goal
4
+
5
+ Add incoming message handling to the WhatsApp Cloud SDK. Since this is a **client SDK** (not a server framework), we need to provide:
6
+ 1. **Webhook verification utilities** - Help verify GET requests from Meta
7
+ 2. **Signature validation utilities** - Validate POST request signatures
8
+ 3. **Webhook payload parsing** - Parse and validate incoming webhook payloads
9
+ 4. **Message handlers** - Type-safe handler system for processing incoming messages
10
+ 5. **Type definitions** - Complete type safety for incoming messages
11
+
12
+ ## 📋 Key Requirements from Meta Docs
13
+
14
+ ### Webhook Verification (GET)
15
+ - Meta sends: `GET /webhook?hub.mode=subscribe&hub.challenge=<CHALLENGE>&hub.verify_token=<TOKEN>`
16
+ - We must: Compare `hub.verify_token` with our stored token
17
+ - Response: Return `hub.challenge` as plain text with 200 status if valid
18
+
19
+ ### Webhook Signature Validation (POST)
20
+ - Meta sends: `X-Hub-Signature-256: sha256=<HASH>` header
21
+ - We must: Generate HMAC-SHA256 hash using `app_secret` as key
22
+ - Validation: Compare our hash with the header value
23
+
24
+ ### Webhook Payload Structure
25
+ ```json
26
+ {
27
+ "object": "whatsapp_business_account",
28
+ "entry": [{
29
+ "id": "102290129340398",
30
+ "changes": [{
31
+ "value": {
32
+ "messaging_product": "whatsapp",
33
+ "metadata": {
34
+ "display_phone_number": "15550783881",
35
+ "phone_number_id": "106540352242922"
36
+ },
37
+ "contacts": [{ "profile": { "name": "Sheena Nelson" }, "wa_id": "16505551234" }],
38
+ "messages": [{ "from": "16505551234", "id": "wamid...", "timestamp": "1749416383", "type": "text", "text": { "body": "Hello!" } }],
39
+ "statuses": [{ ... }] // For outgoing message status updates
40
+ },
41
+ "field": "messages"
42
+ }]
43
+ }]
44
+ }
45
+ ```
46
+
47
+ ## 🏗️ Architecture Proposal
48
+
49
+ ### 1. Webhooks Service Namespace
50
+
51
+ Similar to `messages`, `accounts`, `business`, we add a `webhooks` namespace:
52
+
53
+ ```typescript
54
+ const client = new WhatsAppClient({
55
+ accessToken: "...",
56
+ appSecret: "...", // Required for signature validation
57
+ });
58
+
59
+ // Webhook utilities
60
+ client.webhooks.verify(request) // Verify GET request
61
+ client.webhooks.validateSignature(request, body) // Validate POST signature
62
+ client.webhooks.parse(payload) // Parse webhook payload
63
+ ```
64
+
65
+ ### 2. Incoming Message Types & Schemas
66
+
67
+ Create schemas for incoming messages (mirroring outgoing structure):
68
+
69
+ ```
70
+ src/
71
+ ├── schemas/
72
+ │ └── webhooks/
73
+ │ ├── index.ts
74
+ │ ├── payload.ts # WebhookPayloadSchema
75
+ │ ├── incoming-message.ts # IncomingMessage schemas (text, image, audio, etc.)
76
+ │ └── status.ts # Message status update schemas
77
+ ├── types/
78
+ │ └── webhooks/
79
+ │ ├── index.ts
80
+ │ ├── payload.ts
81
+ │ ├── incoming-message.ts
82
+ │ └── status.ts
83
+ ```
84
+
85
+ ### 3. Handler System
86
+
87
+ Provide a handler system that users can implement:
88
+
89
+ ```typescript
90
+ // User's handler implementation
91
+ const handlers = {
92
+ text: async (message: IncomingTextMessage, context: MessageContext) => {
93
+ // Process text message
94
+ return { messages: [{ type: "text", text: { body: "Hello back!" } }] };
95
+ },
96
+ image: async (message: IncomingImageMessage, context: MessageContext) => {
97
+ // Process image message
98
+ return { messages: [] };
99
+ },
100
+ };
101
+
102
+ // SDK provides the router/dispatcher
103
+ const result = await client.webhooks.handle(payload, handlers);
104
+ ```
105
+
106
+ ## 🔧 Implementation Details
107
+
108
+ ### Option A: Framework-Agnostic Utilities (Recommended)
109
+
110
+ **Pros:**
111
+ - Works with any framework (Express, Hono, Next.js, etc.)
112
+ - Users implement their own endpoints
113
+ - SDK provides validation/parsing utilities
114
+
115
+ **Cons:**
116
+ - Users need to wire up routes themselves
117
+ - More boilerplate for users
118
+
119
+ **Structure:**
120
+ ```typescript
121
+ // src/services/webhooks/WebhooksService.ts
122
+ export class WebhooksService {
123
+ /**
124
+ * Verify webhook GET request from Meta
125
+ */
126
+ verify(request: { query: { hub_mode?: string; hub_verify_token?: string; hub_challenge?: string } }, verifyToken: string): string | null {
127
+ if (request.query.hub_mode === "subscribe" && request.query.hub_verify_token === verifyToken) {
128
+ return request.query.hub_challenge || null;
129
+ }
130
+ return null;
131
+ }
132
+
133
+ /**
134
+ * Validate webhook POST signature
135
+ */
136
+ validateSignature(body: string, signature: string, appSecret: string): boolean {
137
+ // HMAC-SHA256 validation
138
+ }
139
+
140
+ /**
141
+ * Parse webhook payload
142
+ */
143
+ parse(payload: unknown): WebhookPayload {
144
+ // Validate and parse using Zod schema
145
+ }
146
+
147
+ /**
148
+ * Extract incoming messages from payload
149
+ */
150
+ extractMessages(payload: WebhookPayload): IncomingMessage[] {
151
+ // Flatten messages from nested structure
152
+ }
153
+
154
+ /**
155
+ * Extract status updates from payload
156
+ */
157
+ extractStatuses(payload: WebhookPayload): MessageStatus[] {
158
+ // Extract status updates
159
+ }
160
+ }
161
+ ```
162
+
163
+ ### Option B: Framework Adapters
164
+
165
+ **Pros:**
166
+ - Easier to use for specific frameworks
167
+ - Less boilerplate
168
+
169
+ **Cons:**
170
+ - Need to maintain multiple adapters
171
+ - Framework-specific dependencies
172
+
173
+ **Structure:**
174
+ ```typescript
175
+ // src/adapters/express.ts
176
+ export function createExpressWebhookHandler(client: WhatsAppClient, handlers: MessageHandlers) {
177
+ return async (req: Request, res: Response) => {
178
+ // Handle GET verification
179
+ if (req.method === "GET") {
180
+ const challenge = client.webhooks.verify(req.query, process.env.VERIFY_TOKEN);
181
+ if (challenge) return res.send(challenge);
182
+ return res.status(403).send("Forbidden");
183
+ }
184
+
185
+ // Handle POST messages
186
+ const isValid = client.webhooks.validateSignature(req.body, req.headers["x-hub-signature-256"], process.env.APP_SECRET);
187
+ if (!isValid) return res.status(401).send("Invalid signature");
188
+
189
+ const payload = client.webhooks.parse(req.body);
190
+ await client.webhooks.handle(payload, handlers);
191
+ return res.json({ success: true });
192
+ };
193
+ }
194
+ ```
195
+
196
+ ### Option C: Hybrid Approach (Best of Both)
197
+
198
+ Provide utilities + optional framework helpers:
199
+
200
+ ```typescript
201
+ // Core utilities (always available)
202
+ client.webhooks.verify(...)
203
+ client.webhooks.validateSignature(...)
204
+ client.webhooks.parse(...)
205
+
206
+ // Optional framework helpers (separate exports)
207
+ import { createExpressHandler } from "@whatsapp-cloud/express";
208
+ import { createHonoHandler } from "@whatsapp-cloud/hono";
209
+ ```
210
+
211
+ ## 📦 Proposed File Structure
212
+
213
+ ```
214
+ src/
215
+ ├── services/
216
+ │ └── webhooks/
217
+ │ ├── index.ts
218
+ │ ├── WebhooksService.ts # Core service class
219
+ │ ├── WebhooksClient.ts # (if needed, similar to MessagesClient)
220
+ │ ├── utils/
221
+ │ │ ├── verify.ts # GET verification logic
222
+ │ │ ├── validate-signature.ts # POST signature validation
223
+ │ │ ├── parse-payload.ts # Payload parsing
224
+ │ │ └── extract-messages.ts # Extract messages from payload
225
+ │ └── handlers/
226
+ │ ├── index.ts
227
+ │ ├── types.ts # Handler types
228
+ │ └── dispatcher.ts # Message type dispatcher
229
+ ├── schemas/
230
+ │ └── webhooks/
231
+ │ ├── index.ts
232
+ │ ├── payload.ts # WebhookPayloadSchema
233
+ │ ├── incoming-message.ts # Incoming message schemas
234
+ │ └── status.ts # Status update schemas
235
+ └── types/
236
+ └── webhooks/
237
+ ├── index.ts
238
+ ├── payload.ts
239
+ ├── incoming-message.ts
240
+ └── status.ts
241
+ ```
242
+
243
+ ## 🎨 API Design Examples
244
+
245
+ ### Basic Usage (Framework-Agnostic)
246
+
247
+ ```typescript
248
+ import { WhatsAppClient } from "@whatsapp-cloud/sdk";
249
+ import express from "express";
250
+
251
+ const client = new WhatsAppClient({
252
+ accessToken: process.env.ACCESS_TOKEN,
253
+ appSecret: process.env.APP_SECRET, // For signature validation
254
+ });
255
+
256
+ const app = express();
257
+ app.use(express.json());
258
+
259
+ // GET /webhook - Verification
260
+ app.get("/webhook", (req, res) => {
261
+ const challenge = client.webhooks.verify(req.query, process.env.VERIFY_TOKEN);
262
+ if (challenge) {
263
+ res.send(challenge);
264
+ } else {
265
+ res.status(403).send("Forbidden");
266
+ }
267
+ });
268
+
269
+ // POST /webhook - Incoming messages
270
+ app.post("/webhook", async (req, res) => {
271
+ const signature = req.headers["x-hub-signature-256"] as string;
272
+ const bodyString = JSON.stringify(req.body);
273
+
274
+ // Validate signature
275
+ if (!client.webhooks.validateSignature(bodyString, signature, process.env.APP_SECRET)) {
276
+ return res.status(401).send("Invalid signature");
277
+ }
278
+
279
+ // Parse payload
280
+ const payload = client.webhooks.parse(req.body);
281
+
282
+ // Extract messages
283
+ const messages = client.webhooks.extractMessages(payload);
284
+ const statuses = client.webhooks.extractStatuses(payload);
285
+
286
+ // Process messages
287
+ for (const message of messages) {
288
+ if (message.type === "text") {
289
+ // Handle text message
290
+ await client.messages.sendText({
291
+ to: message.from,
292
+ text: { body: "Echo: " + message.text.body },
293
+ });
294
+ }
295
+ }
296
+
297
+ res.json({ success: true });
298
+ });
299
+ ```
300
+
301
+ ### With Handler System
302
+
303
+ ```typescript
304
+ // Define handlers
305
+ const handlers = {
306
+ text: async (message: IncomingTextMessage, context: MessageContext) => {
307
+ console.log(`Received: ${message.text.body}`);
308
+ return {
309
+ messages: [{
310
+ type: "text" as const,
311
+ text: { body: `You said: ${message.text.body}` },
312
+ }],
313
+ };
314
+ },
315
+ image: async (message: IncomingImageMessage, context: MessageContext) => {
316
+ // Download and process image
317
+ const imageData = await client.webhooks.downloadMedia(message.image.id);
318
+ return { messages: [] };
319
+ },
320
+ };
321
+
322
+ // Use dispatcher
323
+ app.post("/webhook", async (req, res) => {
324
+ // ... validation ...
325
+ const payload = client.webhooks.parse(req.body);
326
+ await client.webhooks.handle(payload, handlers);
327
+ res.json({ success: true });
328
+ });
329
+ ```
330
+
331
+ ## 💾 Database Storage Considerations
332
+
333
+ ### When to Store Messages?
334
+
335
+ **Option 1: Store on Send (Outgoing)**
336
+ ```typescript
337
+ // User sends message
338
+ const response = await client.messages.sendText({ to: "+1234567890", text: { body: "Hello" } });
339
+
340
+ // Store immediately
341
+ await db.messages.create({
342
+ id: response.messages[0].id,
343
+ to: "+1234567890",
344
+ from: phoneNumberId,
345
+ body: "Hello",
346
+ status: "sent", // Initial status
347
+ sentAt: new Date(),
348
+ });
349
+ ```
350
+
351
+ **Pros:**
352
+ - Immediate record in database
353
+ - Can track messages even if webhook fails
354
+ - Good for UI showing "sending..." state
355
+
356
+ **Cons:**
357
+ - Status might be outdated (webhook updates it)
358
+ - Need to handle webhook updates separately
359
+
360
+ **Option 2: Store on Webhook (Status Update)**
361
+ ```typescript
362
+ // User sends message
363
+ await client.messages.sendText({ to: "+1234567890", text: { body: "Hello" } });
364
+
365
+ // Don't store yet, wait for webhook
366
+
367
+ // In webhook handler
368
+ app.post("/webhook", async (req, res) => {
369
+ const payload = client.webhooks.parse(req.body);
370
+ const statuses = client.webhooks.extractStatuses(payload);
371
+
372
+ for (const status of statuses) {
373
+ if (status.status === "sent") {
374
+ // Now store the message
375
+ await db.messages.create({
376
+ id: status.id,
377
+ to: status.recipient_id,
378
+ from: phoneNumberId,
379
+ body: "...", // Problem: we don't have the body!
380
+ status: status.status,
381
+ sentAt: new Date(parseInt(status.timestamp) * 1000),
382
+ });
383
+ }
384
+ }
385
+ });
386
+ ```
387
+
388
+ **Pros:**
389
+ - Single source of truth (webhook)
390
+ - Always has accurate status
391
+
392
+ **Cons:**
393
+ - Status webhook doesn't include message body/content
394
+ - Can't show "sending..." state in UI
395
+ - If webhook fails, message is lost
396
+
397
+ **Option 3: Hybrid Approach (Recommended)**
398
+
399
+ ```typescript
400
+ // 1. Store on send with "pending" status
401
+ const response = await client.messages.sendText({ to: "+1234567890", text: { body: "Hello" } });
402
+
403
+ await db.messages.create({
404
+ id: response.messages[0].id,
405
+ to: "+1234567890",
406
+ from: phoneNumberId,
407
+ body: "Hello",
408
+ status: "pending", // Initial status
409
+ sentAt: new Date(),
410
+ });
411
+
412
+ // 2. Update on webhook status
413
+ app.post("/webhook", async (req, res) => {
414
+ const payload = client.webhooks.parse(req.body);
415
+ const statuses = client.webhooks.extractStatuses(payload);
416
+
417
+ for (const status of statuses) {
418
+ await db.messages.update({
419
+ where: { id: status.id },
420
+ data: {
421
+ status: status.status, // "sent", "delivered", "read", "failed"
422
+ deliveredAt: status.status === "delivered" ? new Date(parseInt(status.timestamp) * 1000) : undefined,
423
+ readAt: status.status === "read" ? new Date(parseInt(status.timestamp) * 1000) : undefined,
424
+ },
425
+ });
426
+ }
427
+ });
428
+ ```
429
+
430
+ **For Incoming Messages:**
431
+ ```typescript
432
+ // Always store on webhook (only source of truth)
433
+ app.post("/webhook", async (req, res) => {
434
+ const payload = client.webhooks.parse(req.body);
435
+ const messages = client.webhooks.extractMessages(payload);
436
+
437
+ for (const message of messages) {
438
+ await db.messages.create({
439
+ id: message.id,
440
+ from: message.from,
441
+ to: phoneNumberId,
442
+ type: message.type,
443
+ body: message.type === "text" ? message.text.body : null,
444
+ receivedAt: new Date(parseInt(message.timestamp) * 1000),
445
+ status: "received",
446
+ });
447
+ }
448
+ });
449
+ ```
450
+
451
+ ## 🎯 Recommended Approach
452
+
453
+ ### Phase 1: Core Utilities (MVP)
454
+ 1. ✅ Webhook verification utility
455
+ 2. ✅ Signature validation utility
456
+ 3. ✅ Payload parsing with Zod schemas
457
+ 4. ✅ Type definitions for incoming messages
458
+ 5. ✅ Extract messages/statuses from payload
459
+
460
+ ### Phase 2: Handler System
461
+ 1. ✅ Handler type definitions
462
+ 2. ✅ Message dispatcher/router
463
+ 3. ✅ Media download utility (for images/audio)
464
+
465
+ ### Phase 3: Framework Helpers (Optional)
466
+ 1. Express adapter
467
+ 2. Hono adapter
468
+ 3. Next.js API route helper
469
+
470
+ ## 🤔 Open Questions
471
+
472
+ 1. **Should we include media download utilities?**
473
+ - Yes, it's a common need and requires auth token
474
+ - Provide: `client.webhooks.downloadMedia(mediaId)`
475
+
476
+ 2. **How to handle multiple phone numbers?**
477
+ - Webhook payload includes `phone_number_id` in metadata
478
+ - Users can filter/route based on this
479
+
480
+ 3. **Should we provide a built-in handler dispatcher?**
481
+ - Yes, but make it optional
482
+ - Users can also manually iterate messages
483
+
484
+ 4. **Error handling strategy?**
485
+ - Validation errors throw (invalid signature, malformed payload)
486
+ - Handler errors should be caught and logged (don't break webhook response)
487
+
488
+ 5. **Status updates - separate handler?**
489
+ - Yes, provide separate handler type for status updates
490
+ - Many apps only care about messages, not statuses
491
+
492
+ ## 📝 Next Steps
493
+
494
+ 1. Create schemas for incoming messages (mirror outgoing structure)
495
+ 2. Implement webhook verification utility
496
+ 3. Implement signature validation utility
497
+ 4. Create WebhooksService class
498
+ 5. Add to WhatsAppClient namespace
499
+ 6. Write examples and documentation
500
+
@@ -0,0 +1,112 @@
1
+ Nav-Logo
2
+ Build with us
3
+ Docs
4
+ Blog
5
+ Resources
6
+ Developer centers
7
+ Meine Apps
8
+ Dokumente
9
+ Übersicht
10
+ Webhook-Endpunkt erstellen
11
+ Webhook-Endpunkt erstellen
12
+ Aktualisiert: 07.11.2025
13
+ Erfahre mehr über Webhook-Anfragen und -Antworten, damit du deinen eigenen Webhook-Endpunkt auf einem öffentlichen Server einrichten und konfigurieren kannst.
14
+ Bevor du deine App in einer Produktionsumgebung nutzen kannst, musst du deinen eigenen Webhook-Endpunkt auf einem öffentlichen Server erstellen und konfigurieren, der GET- und POST-Anfragen empfangen und beantworten sowie Webhook-Payloads validieren und erfassen kann.
15
+ TLS/SSL
16
+ Der Server des Webhook-Endpunkts muss über ein korrekt konfiguriertes und installiertes digitales TLS- oder SSL-Sicherheitszertifikat verfügen. Selbstsignierte Zertifikate werden nicht unterstützt.
17
+ mTLS
18
+ Webhooks unterstützen für zusätzliche Sicherheit gegenseitiges TLS (mutual TLS, mTLS). Im Dokument mTLS für Webhooks der Graph API erfährst du, wie du mTLS aktivieren und verwenden kannst.
19
+ Beachte, dass das Aktivieren und Deaktivieren von mTLS nicht auf der Ebene eines WABA oder einer Unternehmenstelefonnummer unterstützt wird. Wenn mehr als eine App auf die Plattform zugreift, musst du mTLS für jede App aktivieren.
20
+ GET-Anfragen
21
+ GET-Anfragen werden verwendet, um deinen Webhook-Endpunkt zu verifizieren. Jedes Mal, wenn du im App-Dashboard das Feld Rückruf-URL oder Verifizierungstoken festlegst oder bearbeitest, senden wir eine GET-Anfrage an deinen Webhook-Endpunkt. Du musst diese Anfrage validieren und auf sie antworten.
22
+ Anfragesyntax
23
+ GET <CALLBACK_URL>
24
+ ?hub.mode=subscribe
25
+ &hub.challenge=<HUB.CHALLENGE>
26
+ &hub.verify_token=<HUB.VERIFY_TOKEN>
27
+ Anfrageparameter
28
+ Platzhalter Beschreibung Beispielwert
29
+ <CALLBACK_URL>
30
+ Die URL deines Webhook-Endpunkts
31
+ Füge diese URL im App-Dashboard im Feld Rückruf-URL hinzu, wenn du später Webhooks konfigurierst.
32
+ https://www.luckyshrub.com/webhooks
33
+ <HUB.CHALLENGE>
34
+ Ein zufälliger String, den wir generieren
35
+ 1158201444
36
+ <HUB.VERIFY_TOKEN>
37
+ Ein Verifizierungs-String deiner Wahl. Speichere diesen String auf deinem Server.
38
+ Füge diesen String später beim Konfigurieren von Webhooks im Feld Verifizierungstoken im App-Dashboard hinzu.
39
+ vibecoding
40
+ Validierung
41
+ Um GET-Anfragen zu validieren, vergleiche den hub.verify_token-Wert in der Anfrage mit dem Verifizierungs-String, den du auf deinem Server gespeichert hast. Stimmen die Werte überein, ist die Anfrage gültig, andernfalls ist sie ungültig.
42
+ Antwort
43
+ Wenn die Anfrage gültig ist, antworte mit dem HTTP-Status 200 und dem hub.challenge-Wert. Wenn die Anfrage ungültig ist, antworte mit einem HTTP-Statuscode auf der 400er-Ebene oder mit einem anderen Status als 200.
44
+ Wenn du Webhooks konfigurierst, senden wir eine GET-Anfrage an deinen Webhook-Endpunkt. Wenn der Status 200 und der in der Anfrage enthaltene hub.challenge-Wert zurückgesendet werden, betrachten wir deinen Webhook-Endpunkt als verifiziert und beginnen damit, dir Webhooks zu senden. Wenn dein Webhook-Endpunkt mit einer anderen Antwort reagiert, betrachten wir deinen Webhook-Endpunkt jedoch als nicht verifiziert und es werden keine Webhooks an deinen Endpunkt gesendet.
45
+ POST-Anfragen
46
+ Jedes Mal, wenn ein Webhook-Event für Webhook-Felder ausgelöst wird, die du abonniert hast, wird eine POST-Anfrage an deinen Webhook-Endpunkt gesendet. Sie enthält eine JSON-Payload mit einer Beschreibung des Events.
47
+ Anfragesyntax
48
+ POST <CALLBACK_URL>
49
+ Content-Type: application/json
50
+ X-Hub-Signature-256: sha256=<SHA256_PAYLOAD_HASH>
51
+ Content-Length: <CONTENT_LENGTH><JSON_PAYLOAD>
52
+ Anfrageparameter
53
+ Platzhalter Beschreibung Beispielwert
54
+ <CALLBACK_URL>
55
+ Die URL deines Webhook-Endpunkts
56
+ https://www.luckyshrub.com/webhooks
57
+ <CONTENT_LENGTH>
58
+ Inhaltslänge in Byte
59
+ 492
60
+ <JSON_PAYLOAD>
61
+ Post-Text-Payload, formatiert als JSON
62
+ In den Referenzen zu den Feldern findest du Beispiel-Payloads.
63
+ <SHA256_PAYLOAD_HASH>
64
+ HMAC-SHA256-Hash, berechnet aus dem Text der POST-Payload und deinem App-Geheimcode als Secret Key.
65
+ b63bb356dff0f1c24379efea2d6ef0b2e2040853339d1bcf13f9018790b1f7d2
66
+ Validierung
67
+ So validierst du die Anfrage:
68
+ Generiere einen HMAC-SHA256-Hash mit der JSON-Payload als Nachrichteneingabe und deinem App-Geheimcode als Secret Key. Vergleiche deinen generierten Hash mit dem Hash, der dem X-Hub-Signature-256-Header (alles nach sha256=) zugewiesen ist.
69
+ Stimmen die Hashes überein, ist die Payload gültig. Erfasse die Payload und verarbeite ihren Inhalt je nach Geschäftsanforderungen. Wenn sie nicht übereinstimmen, kannst du die Payload als ungültig betrachten.
70
+ Beachte, dass wir keine APIs zum Abrufen von Webhook-Verlaufsdaten anbieten. Du musst also entsprechend die Webhook-Payload erfassen und speichern.
71
+ Antwort
72
+ Wenn die Anfrage gültig ist, antworte mit dem HTTP-Status 200. Andernfalls sendest du eine Antwort mit einem HTTP-Status der 400er-Ebene oder mit einem anderen Status als 200.
73
+ Batching
74
+ POST-Anfragen werden in einem Batch mit maximal 1.000 Aktualisierungen aggregiert und gesendet. Die Zusammenfassung in Batches kann jedoch nicht garantiert werden, also passe deine Server so an, dass sie jede POST-Anfrage einzeln verarbeiten können.
75
+ Wenn eine an deinen Server gesendete POST-Anfrage fehlschlägt, wiederholen wir den Vorgang unmittelbar und starten anschließend in immer größeren Abständen innerhalb der nächsten 36 Stunden weitere Wiederholungsversuche. Dein Server sollte in diesen Fällen eine Deduplizierung durchführen können.
76
+ Antworten, die nicht innerhalb von 36 Stunden bestätigt werden, werden gelöscht.
77
+ Webhooks konfigurieren
78
+ Nachdem du deinen Webhook-Endpunkt erstellt hast, navigiere zum Bereich App-Dashboard > WhatsApp > Konfiguration und füge im Feld Rückruf-URL die URL deines Webhook-Endpunkts und im Feld Verifizierungstoken deinen Verifizierungs-String hinzu.
79
+ Hinweis: Wenn du deine App mit dem Anwendungsfall Über WhatsApp mit deinen Kunden in Kontakt treten erstellt hast, navigiere stattdessen zu App-Dashboard > Anwendungsfälle > Anpassen > Konfiguration.
80
+
81
+ Wenn dein Webhook-Endpunkt auf GET-Anfragen zur Webhook-Verifizierung korrekt antwortet, werden deine Änderungen im Bereich gespeichert und es wird eine Liste der Felder angezeigt, die du abonnieren kannst. Anschließend kannst du die Felder abonnieren, die deinen geschäftlichen Anforderungen entsprechen.
82
+ Beachte, dass du den Endpunkt POST Application Subscriptions verwenden kannst, um Webhooks als alternative Methode zu konfigurieren. Dazu ist allerdings ein App-Token erforderlich. Im Dokument Subscriptions-Edge der Graph API erfährst du, wie das geht. Verwende dabei „whatsapp_business_account“ als Objektwert.
83
+ War diese Seite hilfreich?
84
+ „Daumen hoch“-Symbol
85
+ „Daumen runter“-Symbol
86
+ Meta
87
+ FacebookInstagramXLinkedInYouTube
88
+ Build with Meta
89
+ AI
90
+ Meta Horizon
91
+ Social technologies
92
+ Wearables
93
+ News
94
+ Meta for Developers
95
+ Blog
96
+ Success stories
97
+ Support
98
+ Developer Support
99
+ Bug tool
100
+ Platform status
101
+ Developer community forum
102
+ Report an incident
103
+ About us
104
+ About
105
+ Careers
106
+ Terms and policies
107
+ Responsible platform initiatives
108
+ Platform terms
109
+ Developer policies
110
+ Privacy policy
111
+ Cookies
112
+ English (US)