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.
- package/CHANGELOG.md +13 -0
- package/README.md +11 -0
- package/agent_docs/DESIGN.md +707 -0
- package/agent_docs/INCOMING_MESSAGES_BRAINSTORM.md +500 -0
- package/agent_docs/MESSAGES_NAMESPACE_ANALYSIS.md +368 -0
- package/agent_docs/NAMING_DECISION.md +78 -0
- package/agent_docs/STRUCTURE.md +711 -0
- package/agent_docs/messages-namespace-design.md +357 -0
- package/cloud-api-docs/webhooks/endpoint.md +112 -0
- package/cloud-api-docs/webhooks/overview.md +154 -0
- package/package.json +10 -3
- package/src/client/HttpClient.ts +159 -0
- package/src/client/WhatsAppClient.ts +58 -0
- package/src/client/index.ts +2 -0
- package/src/errors.ts +58 -0
- package/src/examples/main.ts +9 -0
- package/src/examples/template.ts +134 -0
- package/src/index.ts +16 -1
- package/src/schemas/accounts/index.ts +1 -0
- package/src/schemas/accounts/phone-number.ts +20 -0
- package/src/schemas/business/account.ts +43 -0
- package/src/schemas/business/index.ts +2 -0
- package/src/schemas/client.ts +50 -0
- package/src/schemas/debug.ts +25 -0
- package/src/schemas/index.ts +6 -0
- package/src/schemas/messages/index.ts +2 -0
- package/src/schemas/messages/request.ts +82 -0
- package/src/schemas/messages/response.ts +19 -0
- package/src/schemas/templates/component.ts +145 -0
- package/src/schemas/templates/index.ts +4 -0
- package/src/schemas/templates/request.ts +78 -0
- package/src/schemas/templates/response.ts +64 -0
- package/src/services/accounts/AccountsClient.ts +34 -0
- package/src/services/accounts/AccountsService.ts +45 -0
- package/src/services/accounts/index.ts +2 -0
- package/src/services/accounts/methods/list-phone-numbers.ts +15 -0
- package/src/services/business/BusinessClient.ts +34 -0
- package/src/services/business/BusinessService.ts +45 -0
- package/src/services/business/index.ts +3 -0
- package/src/services/business/methods/list-accounts.ts +17 -0
- package/src/services/index.ts +2 -0
- package/src/services/messages/MessagesClient.ts +34 -0
- package/src/services/messages/MessagesService.ts +97 -0
- package/src/services/messages/index.ts +8 -0
- package/src/services/messages/methods/send-image.ts +33 -0
- package/src/services/messages/methods/send-location.ts +32 -0
- package/src/services/messages/methods/send-reaction.ts +33 -0
- package/src/services/messages/methods/send-text.ts +32 -0
- package/src/services/messages/utils/build-message-payload.ts +32 -0
- package/src/services/templates/TemplatesClient.ts +35 -0
- package/src/services/templates/TemplatesService.ts +117 -0
- package/src/services/templates/index.ts +3 -0
- package/src/services/templates/methods/create.ts +27 -0
- package/src/services/templates/methods/delete.ts +38 -0
- package/src/services/templates/methods/get.ts +23 -0
- package/src/services/templates/methods/list.ts +36 -0
- package/src/services/templates/methods/update.ts +35 -0
- package/src/types/accounts/index.ts +1 -0
- package/src/types/accounts/phone-number.ts +9 -0
- package/src/types/business/account.ts +10 -0
- package/src/types/business/index.ts +2 -0
- package/src/types/client.ts +8 -0
- package/src/types/debug.ts +8 -0
- package/src/types/index.ts +6 -0
- package/src/types/messages/index.ts +2 -0
- package/src/types/messages/request.ts +27 -0
- package/src/types/messages/response.ts +7 -0
- package/src/types/templates/component.ts +33 -0
- package/src/types/templates/index.ts +4 -0
- package/src/types/templates/request.ts +28 -0
- package/src/types/templates/response.ts +34 -0
- package/src/utils/zod-error.ts +28 -0
- 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.
|
|
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
|
}
|