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
@@ -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)
@@ -0,0 +1,154 @@
1
+ # Development Guide
2
+
3
+ ## Local Development with npm/pnpm link
4
+
5
+ To test the SDK in your own project without publishing to npm:
6
+
7
+ ### Step 1: Link the package (in whatsapp-cloud directory)
8
+
9
+ ```bash
10
+ cd /Users/lukas/Developer/whatsapp-cloud
11
+ pnpm build # Build the package first
12
+ pnpm link --global # Creates a global symlink
13
+ ```
14
+
15
+ Or with npm:
16
+
17
+ ```bash
18
+ npm link
19
+ ```
20
+
21
+ ### Step 2: Link in your project
22
+
23
+ ```bash
24
+ cd /path/to/your/project
25
+ pnpm link whatsapp-cloud
26
+ ```
27
+
28
+ Or with npm:
29
+
30
+ ```bash
31
+ npm link whatsapp-cloud
32
+ ```
33
+
34
+ **What this does:** Creates a symlink in your project's `node_modules` pointing to your local package. You don't need to:
35
+
36
+ - Add it to `package.json` (link handles it)
37
+ - Run `pnpm install` (link is enough)
38
+ - Publish to npm
39
+
40
+ ### Step 3: Use it in your project
41
+
42
+ ```typescript
43
+ import { WhatsAppClient, type IncomingTextMessage } from "whatsapp-cloud";
44
+
45
+ const client = new WhatsAppClient({
46
+ accessToken: "...",
47
+ });
48
+ ```
49
+
50
+ ### Important Notes
51
+
52
+ - **Rebuild after changes**: After making changes to whatsapp-cloud, run `pnpm build` in the whatsapp-cloud directory
53
+ - **Hot reload**: Some bundlers (like Next.js) may need a restart to pick up changes
54
+ - **Unlink**: When done, unlink with `pnpm unlink whatsapp-cloud` in your project
55
+
56
+ ## Production / CI/CD
57
+
58
+ For production builds and CI/CD, you have a few options:
59
+
60
+ ### Option 1: Publish to npm (Recommended)
61
+
62
+ Once ready, publish the package:
63
+
64
+ ```bash
65
+ cd /Users/lukas/Developer/whatsapp-cloud
66
+ pnpm publish
67
+ ```
68
+
69
+ Then in your project's `package.json`:
70
+
71
+ ```json
72
+ {
73
+ "dependencies": {
74
+ "whatsapp-cloud": "^0.0.5"
75
+ }
76
+ }
77
+ ```
78
+
79
+ ### Option 2: Git dependency (For private repos)
80
+
81
+ If your repo is private, use git dependency:
82
+
83
+ ```json
84
+ {
85
+ "dependencies": {
86
+ "whatsapp-cloud": "git+https://github.com/your-username/whatsapp-cloud.git"
87
+ }
88
+ }
89
+ ```
90
+
91
+ ### Option 3: Local file path (For monorepos)
92
+
93
+ If both projects are in the same repo/monorepo:
94
+
95
+ ```json
96
+ {
97
+ "dependencies": {
98
+ "whatsapp-cloud": "file:../whatsapp-cloud"
99
+ }
100
+ }
101
+ ```
102
+
103
+ ### Option 4: Conditional linking (Dev vs Prod)
104
+
105
+ Use environment detection:
106
+
107
+ ```json
108
+ {
109
+ "dependencies": {
110
+ "whatsapp-cloud": process.env.NODE_ENV === "development"
111
+ ? "link:../whatsapp-cloud"
112
+ : "^0.0.5"
113
+ }
114
+ }
115
+ ```
116
+
117
+ **Note:** For CI/CD, you'll need Option 1 (npm publish) or Option 2 (git dependency). `pnpm link` only works locally.
118
+
119
+ ## Type Exports
120
+
121
+ All types are properly exported and can be imported in React/Next.js projects:
122
+
123
+ ```typescript
124
+ // Import client
125
+ import { WhatsAppClient } from "whatsapp-cloud";
126
+
127
+ // Import types
128
+ import type {
129
+ IncomingTextMessage,
130
+ IncomingMessage,
131
+ WebhookPayload,
132
+ MessageContext,
133
+ CreateTemplateRequest,
134
+ // ... all other types
135
+ } from "whatsapp-cloud";
136
+
137
+ // Import schemas (for validation)
138
+ import {
139
+ incomingTextMessageSchema,
140
+ webhookPayloadSchema,
141
+ // ... all other schemas
142
+ } from "whatsapp-cloud";
143
+ ```
144
+
145
+ ## Verifying Exports
146
+
147
+ To verify all types are exported correctly:
148
+
149
+ ```bash
150
+ # In your project
151
+ pnpm exec tsc --noEmit --skipLibCheck
152
+ ```
153
+
154
+ This will check that all imported types are available.
@@ -0,0 +1,76 @@
1
+ # Webhooks
2
+
3
+ Handle incoming WhatsApp messages and status updates via webhooks.
4
+
5
+ ## Quick Start
6
+
7
+ ```typescript
8
+ import { WhatsAppClient } from "@whatsapp-cloud/sdk";
9
+
10
+ const client = new WhatsAppClient({
11
+ accessToken: process.env.WHATSAPP_ACCESS_TOKEN!,
12
+ });
13
+
14
+ // In your webhook endpoint
15
+ app.post("/webhook", async (req, res) => {
16
+ // handle() returns IMMEDIATELY - handlers run in background
17
+ client.webhooks.handle(req.body, {
18
+ text: async (message, context) => {
19
+ // This can take as long as needed (20s, 1min, etc.)
20
+ // Webhook already returned 200, so Meta is happy
21
+
22
+ // Process text message
23
+ console.log(`Received: ${message.text.body} from ${message.from}`);
24
+
25
+ // Store in database
26
+ await db.messages.create({
27
+ id: message.id,
28
+ from: message.from,
29
+ body: message.text.body,
30
+ phoneNumberId: context.metadata.phoneNumberId,
31
+ });
32
+
33
+ // Send response
34
+ await client.messages.sendText({
35
+ to: `+${message.from}`,
36
+ text: { body: "Got it!" },
37
+ });
38
+ },
39
+ });
40
+
41
+ // Returns 200 IMMEDIATELY (handlers continue in background)
42
+ res.json({ success: true });
43
+ });
44
+ ```
45
+
46
+ ## Webhook Verification
47
+
48
+ Meta sends GET requests to verify your webhook endpoint:
49
+
50
+ ```typescript
51
+ app.get("/webhook", (req, res) => {
52
+ const challenge = client.webhooks.verify(req.query, process.env.VERIFY_TOKEN);
53
+ if (challenge) {
54
+ return res.send(challenge);
55
+ }
56
+ return res.status(403).send("Forbidden");
57
+ });
58
+ ```
59
+
60
+ ## Low-Level API
61
+
62
+ For more control, extract messages manually:
63
+
64
+ ```typescript
65
+ const messages = client.webhooks.extractMessages(payload);
66
+ for (const message of messages) {
67
+ // Custom processing
68
+ }
69
+ ```
70
+
71
+ ## API Reference
72
+
73
+ - `client.webhooks.verify(query, token)` - Verify GET request, returns challenge or null
74
+ - `client.webhooks.extractMessages(payload)` - Extract messages from payload
75
+ - `client.webhooks.extractStatuses(payload)` - Extract status updates
76
+ - `client.webhooks.handle(payload, handlers, options?)` - Handle with type-safe callbacks
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "whatsapp-cloud",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
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",
@@ -11,7 +11,10 @@
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
  },
17
20
  "dependencies": {
@@ -19,6 +22,7 @@
19
22
  },
20
23
  "scripts": {
21
24
  "build": "tsup src/index.ts --format cjs,esm --dts",
22
- "lint": "tsc"
25
+ "lint": "tsc",
26
+ "example": "tsx src/examples/main.ts"
23
27
  }
24
28
  }
@@ -1,5 +1,12 @@
1
1
  import type { ClientConfig } from "../types/client";
2
2
 
3
+ interface APIErrorResponse {
4
+ error?: {
5
+ message?: string;
6
+ code?: number;
7
+ };
8
+ }
9
+
3
10
  /**
4
11
  * HTTP client for making requests to the WhatsApp Cloud API
5
12
  */
@@ -42,12 +49,12 @@ export class HttpClient {
42
49
  });
43
50
 
44
51
  if (!response.ok) {
45
- const error = await response.json().catch(() => ({
52
+ const error = (await response.json().catch(() => ({
46
53
  error: {
47
54
  message: response.statusText,
48
55
  code: response.status,
49
56
  },
50
- }));
57
+ }))) as APIErrorResponse;
51
58
  throw new Error(
52
59
  `API Error: ${error.error?.message || response.statusText} (${
53
60
  error.error?.code || response.status
@@ -72,12 +79,12 @@ export class HttpClient {
72
79
  });
73
80
 
74
81
  if (!response.ok) {
75
- const error = await response.json().catch(() => ({
82
+ const error = (await response.json().catch(() => ({
76
83
  error: {
77
84
  message: response.statusText,
78
85
  code: response.status,
79
86
  },
80
- }));
87
+ }))) as APIErrorResponse;
81
88
  throw new Error(
82
89
  `API Error: ${error.error?.message || response.statusText} (${
83
90
  error.error?.code || response.status
@@ -104,12 +111,42 @@ export class HttpClient {
104
111
  });
105
112
 
106
113
  if (!response.ok) {
107
- const error = await response.json().catch(() => ({
114
+ const error = (await response.json().catch(() => ({
115
+ error: {
116
+ message: response.statusText,
117
+ code: response.status,
118
+ },
119
+ }))) as APIErrorResponse;
120
+ throw new Error(
121
+ `API Error: ${error.error?.message || response.statusText} (${
122
+ error.error?.code || response.status
123
+ })`
124
+ );
125
+ }
126
+
127
+ return response.json() as Promise<T>;
128
+ }
129
+
130
+ /**
131
+ * Make a DELETE request
132
+ */
133
+ async delete<T>(path: string): Promise<T> {
134
+ const url = `${this.baseURL}/${this.apiVersion}${path}`;
135
+
136
+ const response = await fetch(url, {
137
+ method: "DELETE",
138
+ headers: {
139
+ Authorization: `Bearer ${this.accessToken}`,
140
+ },
141
+ });
142
+
143
+ if (!response.ok) {
144
+ const error = (await response.json().catch(() => ({
108
145
  error: {
109
146
  message: response.statusText,
110
147
  code: response.status,
111
148
  },
112
- }));
149
+ }))) as APIErrorResponse;
113
150
  throw new Error(
114
151
  `API Error: ${error.error?.message || response.statusText} (${
115
152
  error.error?.code || response.status
@@ -4,6 +4,8 @@ import { HttpClient } from "./HttpClient";
4
4
  import { MessagesService } from "../services/messages/index";
5
5
  import { AccountsService } from "../services/accounts/index";
6
6
  import { BusinessService } from "../services/business/index";
7
+ import { TemplatesService } from "../services/templates/index";
8
+ import { WebhooksService } from "../services/webhooks/index";
7
9
  import { ZodError } from "zod";
8
10
  import { transformZodError } from "../utils/zod-error";
9
11
  import type { DebugTokenResponse } from "../types/debug";
@@ -15,6 +17,8 @@ export class WhatsAppClient {
15
17
  public readonly messages: MessagesService;
16
18
  public readonly accounts: AccountsService;
17
19
  public readonly business: BusinessService;
20
+ public readonly templates: TemplatesService;
21
+ public readonly webhooks: WebhooksService;
18
22
 
19
23
  private readonly httpClient: HttpClient;
20
24
 
@@ -37,6 +41,8 @@ export class WhatsAppClient {
37
41
  this.messages = new MessagesService(this.httpClient);
38
42
  this.accounts = new AccountsService(this.httpClient);
39
43
  this.business = new BusinessService(this.httpClient);
44
+ this.templates = new TemplatesService(this.httpClient);
45
+ this.webhooks = new WebhooksService(this.httpClient);
40
46
  }
41
47
 
42
48
  /**
@@ -0,0 +1,9 @@
1
+ import "dotenv/config";
2
+ import { WhatsAppClient } from "../client";
3
+
4
+ const client = new WhatsAppClient({
5
+ accessToken: process.env.WHATSAPP_ACCESS_TOKEN!,
6
+ });
7
+
8
+ const debugInfo = await client.debugToken();
9
+ console.log(debugInfo);
@@ -0,0 +1,134 @@
1
+ import "dotenv/config";
2
+ import { WhatsAppClient } from "../client";
3
+
4
+ const client = new WhatsAppClient({
5
+ accessToken: process.env.WHATSAPP_ACCESS_TOKEN!,
6
+ businessAccountId: process.env.WHATSAPP_BUSINESS_ACCOUNT_ID!,
7
+ });
8
+
9
+ async function testTemplates() {
10
+ try {
11
+ console.log("🧪 Testing Templates API...\n");
12
+
13
+ // Test 1: Create a template
14
+ console.log("1️⃣ Creating template...");
15
+ const createResponse = await client.templates.create({
16
+ name: `test_template_${Date.now()}`, // Unique name to avoid conflicts
17
+ language: "en",
18
+ category: "UTILITY",
19
+ components: [
20
+ {
21
+ type: "BODY",
22
+ text: "Hello! This is a test template. Thank you for testing our WhatsApp Cloud API SDK.",
23
+ },
24
+ {
25
+ type: "FOOTER",
26
+ text: "This is a test footer",
27
+ },
28
+ {
29
+ type: "BUTTONS",
30
+ buttons: [
31
+ {
32
+ type: "QUICK_REPLY",
33
+ text: "Get Started",
34
+ },
35
+ {
36
+ type: "QUICK_REPLY",
37
+ text: "Learn More",
38
+ },
39
+ ],
40
+ },
41
+ ],
42
+ });
43
+
44
+ console.log("✅ Template created successfully!");
45
+ console.log("Response:", JSON.stringify(createResponse, null, 2));
46
+ console.log("\n");
47
+
48
+ // Verify create response structure
49
+ if (!createResponse.id) {
50
+ throw new Error("Create response missing 'id' field");
51
+ }
52
+ if (!createResponse.status) {
53
+ throw new Error("Create response missing 'status' field");
54
+ }
55
+ if (!createResponse.category) {
56
+ throw new Error("Create response missing 'category' field");
57
+ }
58
+ console.log("✅ Create response structure verified\n");
59
+
60
+ // Test 2: Get template by ID
61
+ console.log("2️⃣ Getting template by ID...");
62
+ const templateId = createResponse.id;
63
+ const getResponse = await client.templates.get(templateId);
64
+
65
+ console.log("✅ Template retrieved successfully!");
66
+ console.log("Response:", JSON.stringify(getResponse, null, 2));
67
+ console.log("\n");
68
+
69
+ // Verify get response structure
70
+ if (!getResponse.id) {
71
+ throw new Error("Get response missing 'id' field");
72
+ }
73
+ if (!getResponse.name) {
74
+ throw new Error("Get response missing 'name' field");
75
+ }
76
+ if (!getResponse.language) {
77
+ throw new Error("Get response missing 'language' field");
78
+ }
79
+ if (!getResponse.status) {
80
+ throw new Error("Get response missing 'status' field");
81
+ }
82
+ if (!getResponse.category) {
83
+ throw new Error("Get response missing 'category' field");
84
+ }
85
+ if (!Array.isArray(getResponse.components)) {
86
+ throw new Error("Get response missing 'components' array");
87
+ }
88
+ console.log("✅ Get response structure verified\n");
89
+
90
+ // Verify components
91
+ const bodyComponent = getResponse.components.find((c) => c.type === "BODY");
92
+ if (!bodyComponent) {
93
+ throw new Error("BODY component not found in response");
94
+ }
95
+ if (bodyComponent.type !== "BODY") {
96
+ throw new Error("BODY component type mismatch");
97
+ }
98
+ console.log("✅ Components verified\n");
99
+
100
+ // Test 3: List templates
101
+ console.log("3️⃣ Listing templates...");
102
+ const listResponse = await client.templates.list();
103
+ console.log(`✅ Found ${listResponse.data.length} template(s)`);
104
+ console.log("Response:", JSON.stringify(listResponse, null, 2));
105
+ console.log("\n");
106
+
107
+ // Verify list response structure
108
+ if (!Array.isArray(listResponse.data)) {
109
+ throw new Error("List response missing 'data' array");
110
+ }
111
+ console.log("✅ List response structure verified\n");
112
+
113
+ // Verify our created template is in the list
114
+ const foundTemplate = listResponse.data.find((t) => t.id === templateId);
115
+ if (!foundTemplate) {
116
+ console.log(
117
+ "⚠️ Note: Created template may not appear in list immediately (async processing)"
118
+ );
119
+ } else {
120
+ console.log("✅ Created template found in list\n");
121
+ }
122
+
123
+ console.log("🎉 All tests passed!");
124
+ } catch (error) {
125
+ console.error("❌ Test failed:", error);
126
+ if (error instanceof Error) {
127
+ console.error("Error message:", error.message);
128
+ console.error("Error stack:", error.stack);
129
+ }
130
+ process.exit(1);
131
+ }
132
+ }
133
+
134
+ testTemplates();
package/src/index.ts CHANGED
@@ -7,6 +7,13 @@ export * from "./schemas/index";
7
7
  // Export types (primary export point)
8
8
  export type * from "./types/index";
9
9
 
10
+ // Export webhook handler types (convenience exports)
11
+ export type {
12
+ MessageContext,
13
+ MessageHandlers,
14
+ HandleOptions,
15
+ } from "./services/webhooks/index";
16
+
10
17
  // Export errors for error handling
11
18
  export {
12
19
  WhatsAppError,