whatsapp-cloud 0.0.3 → 0.0.5

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 (73) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +11 -0
  3. package/agent_docs/DESIGN.md +707 -0
  4. package/agent_docs/INCOMING_MESSAGES_BRAINSTORM.md +500 -0
  5. package/agent_docs/MESSAGES_NAMESPACE_ANALYSIS.md +368 -0
  6. package/agent_docs/NAMING_DECISION.md +78 -0
  7. package/agent_docs/STRUCTURE.md +711 -0
  8. package/agent_docs/messages-namespace-design.md +357 -0
  9. package/cloud-api-docs/webhooks/endpoint.md +112 -0
  10. package/cloud-api-docs/webhooks/overview.md +154 -0
  11. package/package.json +10 -3
  12. package/src/client/HttpClient.ts +159 -0
  13. package/src/client/WhatsAppClient.ts +58 -0
  14. package/src/client/index.ts +2 -0
  15. package/src/errors.ts +58 -0
  16. package/src/examples/main.ts +9 -0
  17. package/src/examples/template.ts +134 -0
  18. package/src/index.ts +16 -1
  19. package/src/schemas/accounts/index.ts +1 -0
  20. package/src/schemas/accounts/phone-number.ts +20 -0
  21. package/src/schemas/business/account.ts +43 -0
  22. package/src/schemas/business/index.ts +2 -0
  23. package/src/schemas/client.ts +50 -0
  24. package/src/schemas/debug.ts +25 -0
  25. package/src/schemas/index.ts +6 -0
  26. package/src/schemas/messages/index.ts +2 -0
  27. package/src/schemas/messages/request.ts +82 -0
  28. package/src/schemas/messages/response.ts +19 -0
  29. package/src/schemas/templates/component.ts +145 -0
  30. package/src/schemas/templates/index.ts +4 -0
  31. package/src/schemas/templates/request.ts +78 -0
  32. package/src/schemas/templates/response.ts +64 -0
  33. package/src/services/accounts/AccountsClient.ts +34 -0
  34. package/src/services/accounts/AccountsService.ts +45 -0
  35. package/src/services/accounts/index.ts +2 -0
  36. package/src/services/accounts/methods/list-phone-numbers.ts +15 -0
  37. package/src/services/business/BusinessClient.ts +34 -0
  38. package/src/services/business/BusinessService.ts +45 -0
  39. package/src/services/business/index.ts +3 -0
  40. package/src/services/business/methods/list-accounts.ts +17 -0
  41. package/src/services/index.ts +2 -0
  42. package/src/services/messages/MessagesClient.ts +34 -0
  43. package/src/services/messages/MessagesService.ts +97 -0
  44. package/src/services/messages/index.ts +8 -0
  45. package/src/services/messages/methods/send-image.ts +33 -0
  46. package/src/services/messages/methods/send-location.ts +32 -0
  47. package/src/services/messages/methods/send-reaction.ts +33 -0
  48. package/src/services/messages/methods/send-text.ts +32 -0
  49. package/src/services/messages/utils/build-message-payload.ts +32 -0
  50. package/src/services/templates/TemplatesClient.ts +35 -0
  51. package/src/services/templates/TemplatesService.ts +117 -0
  52. package/src/services/templates/index.ts +3 -0
  53. package/src/services/templates/methods/create.ts +27 -0
  54. package/src/services/templates/methods/delete.ts +38 -0
  55. package/src/services/templates/methods/get.ts +23 -0
  56. package/src/services/templates/methods/list.ts +36 -0
  57. package/src/services/templates/methods/update.ts +35 -0
  58. package/src/types/accounts/index.ts +1 -0
  59. package/src/types/accounts/phone-number.ts +9 -0
  60. package/src/types/business/account.ts +10 -0
  61. package/src/types/business/index.ts +2 -0
  62. package/src/types/client.ts +8 -0
  63. package/src/types/debug.ts +8 -0
  64. package/src/types/index.ts +6 -0
  65. package/src/types/messages/index.ts +2 -0
  66. package/src/types/messages/request.ts +27 -0
  67. package/src/types/messages/response.ts +7 -0
  68. package/src/types/templates/component.ts +33 -0
  69. package/src/types/templates/index.ts +4 -0
  70. package/src/types/templates/request.ts +28 -0
  71. package/src/types/templates/response.ts +34 -0
  72. package/src/utils/zod-error.ts +28 -0
  73. package/tsconfig.json +6 -4
@@ -0,0 +1,357 @@
1
+ # Messages Namespace Design
2
+
3
+ This document describes the design patterns and architectural decisions for the Messages namespace. This serves as a blueprint for implementing other namespaces in the WhatsApp Cloud API SDK.
4
+
5
+ ## Core Design Principles
6
+
7
+ ### 1. **Namespace Client Pattern**
8
+
9
+ Each namespace that requires a base path identifier (like `phoneNumberId` for messages) gets its own client wrapper that handles the base path automatically.
10
+
11
+ **Pattern:**
12
+ - Create a `{Namespace}Client` class that wraps `HttpClient`
13
+ - The client automatically prepends the namespace identifier to all paths
14
+ - Methods use simple relative paths (e.g., `/messages`) instead of full paths (e.g., `/${phoneNumberId}/messages`)
15
+
16
+ **Example:**
17
+ ```typescript
18
+ // MessagesClient wraps HttpClient with phoneNumberId as base endpoint
19
+ export class MessagesClient {
20
+ constructor(
21
+ private readonly httpClient: HttpClient,
22
+ private readonly phoneNumberId: string
23
+ ) {}
24
+
25
+ async post<T>(path: string, body: unknown): Promise<T> {
26
+ return this.httpClient.post<T>(`/${this.phoneNumberId}${path}`, body);
27
+ }
28
+ }
29
+ ```
30
+
31
+ **Why:** Treats the namespace identifier (phoneNumberId) as a "client" for that namespace. Different identifiers represent different endpoints, making the abstraction clean and intuitive.
32
+
33
+ ### 2. **Request Structure Matches API**
34
+
35
+ Request schemas match the WhatsApp API structure exactly, minus fields that are handled internally.
36
+
37
+ **Pattern:**
38
+ - Request schemas mirror the API payload structure
39
+ - Exclude: `messaging_product`, `recipient_type`, `type` (added by `buildMessagePayload`)
40
+ - Exclude: `phoneNumberId` (handled at client level)
41
+ - Include: All user-provided fields matching API structure
42
+
43
+ **Example:**
44
+ ```typescript
45
+ // API expects: { to, image: { id?, link?, caption? } }
46
+ // Schema matches: { to, image: { id?, link?, caption? } }
47
+ export const sendImageRequestSchema = baseMessageRequestSchema.extend({
48
+ image: imageSchema, // Matches API structure
49
+ });
50
+ ```
51
+
52
+ **Why:**
53
+ - Reduces transformation logic
54
+ - Makes API documentation directly applicable
55
+ - Clear mapping between user input and API payload
56
+
57
+ ### 3. **Client-Level Configuration**
58
+
59
+ Namespace-specific identifiers (like `phoneNumberId`) are handled at the service construction level, not in individual requests.
60
+
61
+ **Pattern:**
62
+ - Service validates required identifier exists in `HttpClient` at construction
63
+ - Service creates namespace client once with the identifier
64
+ - Methods receive the namespace client, not the raw `HttpClient`
65
+ - No per-request identifier resolution needed
66
+
67
+ **Example:**
68
+ ```typescript
69
+ export class MessagesService {
70
+ private readonly messagesClient: MessagesClient;
71
+
72
+ constructor(httpClient: HttpClient) {
73
+ // Validate identifier at construction
74
+ if (!httpClient.phoneNumberId) {
75
+ throw new WhatsAppValidationError(...);
76
+ }
77
+
78
+ // Create namespace client once
79
+ this.messagesClient = new MessagesClient(httpClient, httpClient.phoneNumberId);
80
+ }
81
+
82
+ async sendImage(request: SendImageRequest) {
83
+ // Method receives namespace client, not HttpClient
84
+ return sendImage(this.messagesClient, request);
85
+ }
86
+ }
87
+ ```
88
+
89
+ **Why:**
90
+ - Identifier is required, so validate early (fail fast)
91
+ - Single source of truth for namespace identifier
92
+ - Methods don't need to handle optional overrides
93
+ - Cleaner method signatures
94
+
95
+ ### 4. **Clean Method Pattern**
96
+
97
+ All methods follow a consistent pattern: validate → extract → build → request.
98
+
99
+ **Pattern:**
100
+ ```typescript
101
+ export async function sendImage(
102
+ messagesClient: MessagesClient,
103
+ request: SendImageRequest
104
+ ): Promise<MessageResponse> {
105
+ // 1. Validate request with schema
106
+ const result = sendImageRequestSchema.safeParse(request);
107
+ if (!result.success) {
108
+ throw transformZodError(result.error);
109
+ }
110
+
111
+ // 2. Extract validated data
112
+ const data = result.data;
113
+
114
+ // 3. Build payload (request structure already matches API)
115
+ const payload = buildMessagePayload(data.to, "image", {
116
+ image: data.image,
117
+ });
118
+
119
+ // 4. Make API request (namespace client handles base path)
120
+ return messagesClient.post<MessageResponse>("/messages", payload);
121
+ }
122
+ ```
123
+
124
+ **Why:**
125
+ - Consistent, predictable flow
126
+ - Easy to understand and maintain
127
+ - Clear separation of concerns
128
+ - Request → result → data trajectory
129
+
130
+ ### 5. **Request → Result → Data Trajectory**
131
+
132
+ The validation flow follows a clear trajectory: request → validation result → validated data.
133
+
134
+ **Pattern:**
135
+ ```typescript
136
+ // Request comes in
137
+ const result = schema.safeParse(request);
138
+
139
+ // Extract validated data
140
+ const data = result.data;
141
+
142
+ // Use data directly (structure matches API)
143
+ const payload = buildMessagePayload(data.to, "image", {
144
+ image: data.image,
145
+ });
146
+ ```
147
+
148
+ **Why:**
149
+ - Clear path from user input to safe API request
150
+ - No intermediate transformations needed
151
+ - Type-safe throughout the flow
152
+
153
+ ### 6. **No Manual Undefined Filtering**
154
+
155
+ Let `JSON.stringify` handle undefined values automatically.
156
+
157
+ **Pattern:**
158
+ ```typescript
159
+ // Don't filter undefined manually
160
+ export function buildMessagePayload(to: string, type: string, content: T) {
161
+ return {
162
+ messaging_product: "whatsapp" as const,
163
+ recipient_type: "individual" as const,
164
+ to,
165
+ type,
166
+ ...content, // undefined values automatically omitted by JSON.stringify
167
+ };
168
+ }
169
+ ```
170
+
171
+ **Why:**
172
+ - `JSON.stringify` automatically omits undefined values
173
+ - Less code, simpler logic
174
+ - No need for `omitUndefined` utilities
175
+
176
+ ## Architecture Layers
177
+
178
+ ### Layer 1: Service (MessagesService)
179
+ - **Responsibility:** Validate namespace requirements, create namespace client
180
+ - **Input:** `HttpClient` (with namespace identifier)
181
+ - **Output:** Namespace client instance
182
+ - **Pattern:** Constructor validation + client creation
183
+
184
+ ### Layer 2: Namespace Client (MessagesClient)
185
+ - **Responsibility:** Handle namespace-specific base path
186
+ - **Input:** `HttpClient` + namespace identifier
187
+ - **Output:** Wrapped client with base path handling
188
+ - **Pattern:** Proxy pattern - wraps HttpClient with path prefix
189
+
190
+ ### Layer 3: Methods (sendImage, sendText, etc.)
191
+ - **Responsibility:** Validate request, build payload, make API call
192
+ - **Input:** Namespace client + request object
193
+ - **Output:** API response
194
+ - **Pattern:** Validate → extract → build → request
195
+
196
+ ### Layer 4: Utilities (buildMessagePayload)
197
+ - **Responsibility:** Add common API fields
198
+ - **Input:** User data
199
+ - **Output:** Complete API payload
200
+ - **Pattern:** Simple object construction
201
+
202
+ ## File Structure
203
+
204
+ ```
205
+ services/messages/
206
+ ├── MessagesService.ts # Service layer - validates & creates client
207
+ ├── MessagesClient.ts # Namespace client - handles base path
208
+ ├── methods/
209
+ │ ├── send-image.ts # Method implementations
210
+ │ ├── send-text.ts
211
+ │ ├── send-location.ts
212
+ │ └── send-reaction.ts
213
+ ├── utils/
214
+ │ └── build-message-payload.ts # Common payload builder
215
+ └── index.ts # Exports
216
+ ```
217
+
218
+ ## Schema Structure
219
+
220
+ ```
221
+ schemas/messages/
222
+ ├── request.ts # Request schemas matching API structure
223
+ └── response.ts # Response schemas
224
+ ```
225
+
226
+ **Request Schema Pattern:**
227
+ ```typescript
228
+ // Base schema (common fields)
229
+ const baseMessageRequestSchema = z.object({
230
+ to: z.string().regex(...),
231
+ });
232
+
233
+ // Type-specific schema (matches API structure)
234
+ const imageSchema = z.object({
235
+ id: z.string().optional(),
236
+ link: z.string().url().optional(),
237
+ caption: z.string().max(1024).optional(),
238
+ }).refine(...);
239
+
240
+ // Combined schema
241
+ export const sendImageRequestSchema = baseMessageRequestSchema.extend({
242
+ image: imageSchema,
243
+ });
244
+ ```
245
+
246
+ ## Type Structure
247
+
248
+ ```
249
+ types/messages/
250
+ ├── request.ts # Request types (inferred from schemas)
251
+ └── response.ts # Response types
252
+ ```
253
+
254
+ **Type Pattern:**
255
+ ```typescript
256
+ // Types are inferred from schemas
257
+ export type SendImageRequest = z.infer<typeof sendImageRequestSchema>;
258
+ ```
259
+
260
+ ## Key Design Decisions
261
+
262
+ ### ✅ Do's
263
+
264
+ 1. **Match API structure in requests** - Makes documentation directly applicable
265
+ 2. **Validate at service construction** - Fail fast, clear errors
266
+ 3. **Use namespace clients** - Clean abstraction for namespace-specific paths
267
+ 4. **Follow consistent method pattern** - Easy to understand and maintain
268
+ 5. **Let JSON.stringify handle undefined** - Simpler code
269
+
270
+ ### ❌ Don'ts
271
+
272
+ 1. **Don't include namespace identifiers in requests** - Handle at client level
273
+ 2. **Don't manually filter undefined** - Let JSON.stringify do it
274
+ 3. **Don't transform request structure unnecessarily** - Match API directly
275
+ 4. **Don't resolve identifiers in methods** - Do it at service level
276
+ 5. **Don't create namespace client per request** - Create once in constructor
277
+
278
+ ## Applying to Other Namespaces
279
+
280
+ When creating a new namespace (e.g., `BusinessAccounts`):
281
+
282
+ 1. **Create namespace client** (`BusinessAccountsClient`)
283
+ - Wrap `HttpClient` with namespace-specific base path
284
+ - Handle namespace identifier (e.g., `businessAccountId`)
285
+
286
+ 2. **Create service** (`BusinessAccountsService`)
287
+ - Validate namespace identifier exists in constructor
288
+ - Create namespace client once
289
+ - Pass client to methods
290
+
291
+ 3. **Create methods** (`getProfile`, `updateProfile`, etc.)
292
+ - Follow validate → extract → build → request pattern
293
+ - Use namespace client, not raw `HttpClient`
294
+ - Match API structure in requests
295
+
296
+ 4. **Create schemas** (`schemas/business-accounts/`)
297
+ - Match API structure exactly
298
+ - Exclude internal fields (handled by utilities)
299
+ - Exclude namespace identifier (handled at client level)
300
+
301
+ 5. **Create types** (`types/business-accounts/`)
302
+ - Infer from schemas using `z.infer`
303
+
304
+ ## Example: Applying Pattern to Business Accounts
305
+
306
+ ```typescript
307
+ // 1. Namespace Client
308
+ export class BusinessAccountsClient {
309
+ constructor(
310
+ private readonly httpClient: HttpClient,
311
+ private readonly businessAccountId: string
312
+ ) {}
313
+
314
+ async get<T>(path: string): Promise<T> {
315
+ return this.httpClient.get<T>(`/${this.businessAccountId}${path}`);
316
+ }
317
+ }
318
+
319
+ // 2. Service
320
+ export class BusinessAccountsService {
321
+ private readonly accountsClient: BusinessAccountsClient;
322
+
323
+ constructor(httpClient: HttpClient) {
324
+ if (!httpClient.businessAccountId) {
325
+ throw new WhatsAppValidationError(...);
326
+ }
327
+ this.accountsClient = new BusinessAccountsClient(
328
+ httpClient,
329
+ httpClient.businessAccountId
330
+ );
331
+ }
332
+
333
+ async getProfile() {
334
+ return getProfile(this.accountsClient);
335
+ }
336
+ }
337
+
338
+ // 3. Method
339
+ export async function getProfile(
340
+ accountsClient: BusinessAccountsClient
341
+ ): Promise<ProfileResponse> {
342
+ return accountsClient.get<ProfileResponse>("/profile");
343
+ }
344
+ ```
345
+
346
+ ## Summary
347
+
348
+ The Messages namespace design provides a clean, consistent pattern for implementing API namespaces:
349
+
350
+ - **Namespace clients** handle base paths automatically
351
+ - **Request structures** match API directly
352
+ - **Service layer** validates and creates clients
353
+ - **Methods** follow a consistent pattern
354
+ - **No manual filtering** - let JSON.stringify handle it
355
+
356
+ This pattern ensures consistency, maintainability, and clarity across all namespaces in the SDK.
357
+
@@ -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)
@@ -0,0 +1,154 @@
1
+ Nav-Logo
2
+ Build with us
3
+ Docs
4
+ Blog
5
+ Resources
6
+ Developer centers
7
+ Meine Apps
8
+ Dokumente
9
+ Übersicht
10
+ Webhooks
11
+ Webhooks
12
+ Aktualisiert: 07.11.2025
13
+ In diesem Dokument werden Webhooks beschrieben und wie sie auf der WhatsApp Business-Plattform verwendet werden.
14
+ Webhooks sind HTTP-Anfragen mit JSON-Payloads, die von Meta-Servern an einen von dir bestimmten Server gesendet werden. Die WhatsApp Business-Plattform verwendet Webhooks, um dich über eingehende Nachrichten, den Status ausgehender Nachrichten und andere wichtige Informationen zu informieren, wie z. B. Änderungen an deinem Kontostatus, Upgrades der Nachrichtenfunktion und Änderungen an der Qualitätsbewertungen deiner Vorlagen.
15
+ Hier siehst du einen Webhook, der eine Nachricht beschreibt, die von einem*einer WhatsApp-Benutzer*in an ein Unternehmen gesendet wurde:
16
+ {
17
+ "object": "whatsapp_business_account",
18
+ "entry": [
19
+ {
20
+ "id": "102290129340398",
21
+ "changes": [
22
+ {
23
+ "value": {
24
+ "messaging_product": "whatsapp",
25
+ "metadata": {
26
+ "display_phone_number": "15550783881",
27
+ "phone_number_id": "106540352242922"
28
+ },
29
+ "contacts": [
30
+ {
31
+ "profile": {
32
+ "name": "Sheena Nelson"
33
+ },
34
+ "wa_id": "16505551234"
35
+ }
36
+ ],
37
+ "messages": [
38
+ {
39
+ "from": "16505551234",
40
+ "id": "wamid.HBgLMTY1MDM4Nzk0MzkVAgASGBQzQTRBNjU5OUFFRTAzODEwMTQ0RgA=",
41
+ "timestamp": "1749416383",
42
+ "type": "text"
43
+ "text": {
44
+ "body": "Does it come in another color?"
45
+ }
46
+ }
47
+ ]
48
+ },
49
+ "field": "messages"
50
+ }
51
+ ]
52
+ }
53
+ ]
54
+ }
55
+
56
+ Einen Webhook-Endpunkt erstellen
57
+ Um Webhooks zu empfangen, musst du einen Webhook-Endpunkt erstellen und konfigurieren. Im Dokument Webhook-Endpunkt erstellen erfährst du, wie du deinen eigenen Endpunkt erstellst.
58
+ Wenn du noch nicht bereit bist, deinen eigenen Endpunkt zu erstellen, kannst du einen Test-Webhook-Endpunkt erstellen, der Webhook-Payloads an die Konsole exportiert. Beachte jedoch, dass du deinen eigenen Endpunkt erstellen musst, bevor du deine App in einer Produktionsumgebung verwenden kannst.
59
+ Berechtigungen
60
+ Du benötigst die folgenden Berechtigungen, um Webhooks zu erhalten:
61
+ whatsapp_business_messaging – für messages-Webhooks
62
+ whatsapp_business_management – für alle anderen Webhooks
63
+ Wenn du ein*e direkte*r Entwickler*in bist, gewähre deiner App über deine*n Systemnutzer*in diese Berechtigungen, wenn du dein Systemtoken generierst.
64
+ Wenn du als Lösungsanbieter*in diese Berechtigungen benötigst, um deinen Unternehmenskunden entsprechende Services zur Verfügung zu stellen, musst du vor der App-Review die Genehmigung für erweiterten Zugriff auf die Berechtigungen erhalten. Erst dann können deine Unternehmenskunden deiner App während des Onboardings diese Berechtigungen erteilen.
65
+ Felder
66
+ Sobald du deinen Webhook-Endpunkt erstellt und konfiguriert hast, kannst du die folgenden Webhook-Felder abonnieren.
67
+ Name des Feldes Beschreibung
68
+ account_alerts
69
+ Der account_alerts-Webhook benachrichtigt dich über Änderungen des Messaging-Limits, des Unternehmensprofils und des Status als offizielles Unternehmenskonto einer Unternehmenstelefonnummer.
70
+ account_review_update
71
+ Der account_review_update-Webhook benachrichtigt dich, wenn ein WhatsApp-Unternehmenskonto hinsichtlich der Einhaltung unserer Richtlinien überprüft wurde.
72
+ account_update
73
+ Der account_update-Webhook benachrichtigt dich über Änderungen an der partnergeführten Unternehmensverifizierung eines WhatsApp-Unternehmenskontos, seiner Berechtigung für den Tarif für internationale Authentifizierung oder seinem Hauptgeschäftsstandort, wenn das Konto mit einem*einer Lösungsanbieter*in geteilt wird, bei Richtlinien- oder Nutzungsbedingungsverstößen oder wenn es gelöscht wird.
74
+ automatic_events
75
+ Der automatic_events-Webhook benachrichtigt dich, wenn wir ein Kauf- oder Lead-Event in einem Chat-Thread zwischen dir und einem*einer WhatsApp-Nutzer*in erkennen, der*die dir über deine Click-to-WhatsApp Ad eine Nachricht gesendet hat. Dazu musst du Berichte für automatische Events aktiviert haben.
76
+ business_capability_update
77
+ Der business_capability_update-Webhook informiert dich über Änderungen der Funktionen für WhatsApp-Unternehmenskonto oder Business-Portfolio (Messaging-Limits, Telefonnummer-Limits usw.).
78
+ history
79
+ Der history-Webhook wird verwendet, um den Chatverlauf in der WhatsApp Business-App eines Unternehmenskunden zu synchronisieren, der von einem*einer Lösungsanbieter*in freigeschaltet wurde.
80
+ message_template_components_update
81
+ Der message_template_components_update-Webhook benachrichtigt dich über Änderungen an den Komponenten einer Vorlage.
82
+ message_template_quality_update
83
+ Der message_template_quality_update-Webhook benachrichtigt dich über Änderungen an der Qualitätsbewertung einer Vorlage.
84
+ message_template_status_update
85
+ Der message_template_status_update-Webhook benachrichtigt dich über Änderungen am Status einer vorhandenen Vorlage.
86
+ messages
87
+ Der messages-Webhook beschreibt Nachrichten, die von einem*einer WhatsApp-Nutzer*in an ein Unternehmen gesendet werden, und den Status von Nachrichten, die von einem Unternehmen an eine*n WhatsApp-Nutzer*in gesendet werden.
88
+ partner_solutions
89
+ Der partner_solutions-Webhook beschreibt Änderungen am Status einer Multi-Partner-Lösung.
90
+ payment_configuration_update
91
+ Der payment_configuration_update-Webhook informiert dich über Änderungen an Zahlungskonfigurationen für die Payments API für Indien und die Payments API für Brasilien.
92
+ phone_number_name_update
93
+ Der phone_number_name_update-Webhook informiert dich über die Verifizierung des Display-Namens der Unternehmenstelefonnummer.
94
+ phone_number_quality_update
95
+ Der phone_number_quality_update-Webhook benachrichtigt dich über Änderungen an der Durchsatzrate einer Unternehmenstelefonnummer.
96
+ security
97
+ Der security-Webhook benachrichtigt dich über Änderungen an den Sicherheitseinstellungen einer Unternehmenstelefonnummer.
98
+ smb_app_state_sync
99
+ Der smb_app_state_sync-Webhook wird zum Synchronisieren von Kontakten von Nutzer*innen der WhatsApp Business-App verwendet, die über eine*n Lösungsanbieter*in freigeschaltet wurden.
100
+ smb_message_echoes
101
+ Der smb_message_echoes-Webhook benachrichtigt dich über Nachrichten, die über die WhatsApp Business-App oder ein begleitendes („verknüpftes“) Gerät von einem Unternehmenskunden gesendet wurden, der über eine*n Lösungsanbieter*in für die Cloud API freigeschaltet wurde.
102
+ template_category_update
103
+ Der template_category_update-Webhook benachrichtigt dich über Änderungen an der Kategorie einer Vorlage.
104
+ user_preferences
105
+ Der user_preferences-Webhook benachrichtigt dich über Änderungen an den Marketing-Nachrichten-Einstellungen eines*einer WhatsApp-Nutzer*in.
106
+ Webhooks überschreiben
107
+ Du kannst einen alternativen Webhook-Endpunkt für messages-Webhooks für dein WhatsApp-Unternehmenskonto (WABA) oder deine Unternehmenstelefonnummer verwenden. Dieser kann für Testzwecke nützlich sein oder wenn du als Lösungsanbieter eindeutige Webhook-Endpunkte für alle deine registrierten Kund\*innen verwenden möchtest.
108
+ In unserem Dokument zu Webhook-Überschreibungen erfährst du, wie du Webhooks überschreiben kannst.
109
+ Payload-Größe
110
+ Payload-Webhooks können bis zu 3 MB groß sein.
111
+ Fehler bei der Webhook-Auslieferung
112
+ Wenn wir eine Webhook-Anfrage an deinen Endpunkt senden und dein Server mit einem anderen HTTP-Statuscode als 200 antwortet oder wenn wir den Webhook aus einem anderen Grund nicht zustellen können, versuchen wir es so lange mit abnehmender Häufigkeit, bis die Anfrage erfolgreich ist, und zwar bis zu 7 Tage lang.
113
+ Beachte, dass Wiederholungsversuche an alle Apps gesendet werden, die Webhooks (und ihre entsprechenden Felder) für das WhatsApp Business-Konto abonniert haben. Dies kann zu doppelten Webhook-Benachrichtigungen führen.
114
+ IP-Adressen
115
+ Du kannst die IP-Adressen unserer Webhook-Server abrufen, indem du in deinem Terminal den folgenden Befehl ausführst:
116
+ whois -h whois.radb.net — '-i origin AS32934' | grep '^route' | awk '{print $2}' | sort
117
+ Wir ändern diese IP-Adressen in regelmäßigen Abständen. Wenn du also unsere Server auf der Positivliste hast, solltest du diese Liste gelegentlich neu erstellen und deine Positivliste entsprechend aktualisieren.
118
+ Problembehandlung
119
+ Wenn du keine Webhooks erhältst:
120
+ Vergewissere dich, dass dein Endpunkt Anfragen akzeptiert.
121
+ Sende eine Test-Payload an deinen Endpunkt über das Panel App-Dashboard > WhatsApp > Konfigurationen.
122
+ Stelle sicher, dass der Live-Modus für deine App aktiviert ist. Wenn deine App im Entwicklungsmodus ist, werden einige Webhooks nicht gesendet.
123
+ Mehr dazu
124
+ Siehe unseren Blogeintrag Implementierung von Webhooks mit Node.js für WhatsApp Business.
125
+ War diese Seite hilfreich?
126
+ „Daumen hoch“-Symbol
127
+ „Daumen runter“-Symbol
128
+ Meta
129
+ FacebookInstagramXLinkedInYouTube
130
+ Build with Meta
131
+ AI
132
+ Meta Horizon
133
+ Social technologies
134
+ Wearables
135
+ News
136
+ Meta for Developers
137
+ Blog
138
+ Success stories
139
+ Support
140
+ Developer Support
141
+ Bug tool
142
+ Platform status
143
+ Developer community forum
144
+ Report an incident
145
+ About us
146
+ About
147
+ Careers
148
+ Terms and policies
149
+ Responsible platform initiatives
150
+ Platform terms
151
+ Developer policies
152
+ Privacy policy
153
+ Cookies
154
+ English (US)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "whatsapp-cloud",
3
- "version": "0.0.3",
4
- "description": "",
3
+ "version": "0.0.5",
4
+ "description": "Work in progress. A WhatsApp client tailored for LLMs—built to actually work.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.mjs",
@@ -11,11 +11,18 @@
11
11
  "license": "MIT",
12
12
  "devDependencies": {
13
13
  "@changesets/cli": "^2.29.8",
14
+ "@types/node": "^25.0.3",
15
+ "dotenv": "^17.2.3",
14
16
  "tsup": "^8.5.1",
17
+ "tsx": "^4.21.0",
15
18
  "typescript": "^5.9.3"
16
19
  },
20
+ "dependencies": {
21
+ "zod": "^4.2.1"
22
+ },
17
23
  "scripts": {
18
24
  "build": "tsup src/index.ts --format cjs,esm --dts",
19
- "lint": "tsc"
25
+ "lint": "tsc",
26
+ "example": "tsx src/examples/main.ts"
20
27
  }
21
28
  }