@wazzapi/wazzapi 0.2.0
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/README.md +232 -0
- package/advanced-examples/custom-fetch.ts +40 -0
- package/advanced-examples/download-media.ts +27 -0
- package/advanced-examples/http-webhook-server.ts +80 -0
- package/dist/index.cjs +1550 -0
- package/dist/index.d.cts +1012 -0
- package/dist/index.d.ts +1012 -0
- package/dist/index.js +1461 -0
- package/docs/README.md +61 -0
- package/docs/authentication.md +37 -0
- package/docs/client.md +68 -0
- package/docs/contacts.md +194 -0
- package/docs/errors.md +57 -0
- package/docs/groups.md +233 -0
- package/docs/media.md +38 -0
- package/docs/messages.md +151 -0
- package/docs/templates.md +76 -0
- package/docs/webhooks.md +101 -0
- package/examples/create-template.ts +10 -0
- package/examples/list-contacts.ts +8 -0
- package/examples/preview-template.ts +9 -0
- package/examples/send-message.ts +10 -0
- package/examples/verify-webhook.ts +33 -0
- package/package.json +57 -0
package/README.md
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# WazzAPI Node SDK
|
|
2
|
+
|
|
3
|
+
Official Node.js and TypeScript SDK for WazzAPI.
|
|
4
|
+
|
|
5
|
+
This package is a modern Node.js and TypeScript SDK for WazzAPI, built with Bun-powered development, typed models, ESM/CJS output, and an API surface that feels natural in TypeScript.
|
|
6
|
+
|
|
7
|
+
Use it to send WhatsApp messages, manage contacts and groups, work with templates, verify webhooks, and download encrypted WhatsApp media.
|
|
8
|
+
|
|
9
|
+
## Highlights
|
|
10
|
+
|
|
11
|
+
- typed `WazzapiClient` with resource-based API access
|
|
12
|
+
- Node.js 20, 22, and 24 support
|
|
13
|
+
- ESM and CommonJS package output
|
|
14
|
+
- bundled declaration files for TypeScript consumers
|
|
15
|
+
- camelCase APIs for idiomatic TS usage
|
|
16
|
+
- snake_case aliases for compatibility with existing naming styles
|
|
17
|
+
- built-in webhook verification helpers
|
|
18
|
+
- encrypted media download and decryption helpers
|
|
19
|
+
- standard and advanced runnable examples
|
|
20
|
+
|
|
21
|
+
## Supported Node.js versions
|
|
22
|
+
|
|
23
|
+
This library supports the following Node.js implementations:
|
|
24
|
+
|
|
25
|
+
- Node.js 20
|
|
26
|
+
- Node.js 22
|
|
27
|
+
- Node.js 24 (LTS)
|
|
28
|
+
|
|
29
|
+
TypeScript consumers are supported as long as their compiler can consume the emitted declaration files.
|
|
30
|
+
|
|
31
|
+
## Warning
|
|
32
|
+
|
|
33
|
+
Do not use this Node.js library in a front-end application. Doing so can expose your WazzAPI credentials to end-users as part of the bundled HTML and JavaScript sent to their browser.
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
### Bun
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
bun add @wazzapi/wazzapi
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### npm
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm install @wazzapi/wazzapi
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Configuration
|
|
50
|
+
|
|
51
|
+
The SDK uses `https://api.wazzapi.com` by default.
|
|
52
|
+
|
|
53
|
+
For most integrations, you only need:
|
|
54
|
+
|
|
55
|
+
- `WAZZAPI_API_KEY`
|
|
56
|
+
|
|
57
|
+
If you plan to receive webhooks, also configure:
|
|
58
|
+
|
|
59
|
+
- `WAZZAPI_WEBHOOK_SECRET`
|
|
60
|
+
|
|
61
|
+
Advanced media examples also use:
|
|
62
|
+
|
|
63
|
+
- `WAZZAPI_MEDIA_URL`
|
|
64
|
+
- `WAZZAPI_MEDIA_KEY`
|
|
65
|
+
- `WAZZAPI_MEDIA_MIMETYPE`
|
|
66
|
+
- `WAZZAPI_MEDIA_FILE_NAME`
|
|
67
|
+
- `WAZZAPI_MEDIA_SHA256`
|
|
68
|
+
- `WAZZAPI_MEDIA_ENC_SHA256`
|
|
69
|
+
|
|
70
|
+
## Quick start
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
import { WazzapiClient } from "@wazzapi/wazzapi";
|
|
74
|
+
|
|
75
|
+
const client = new WazzapiClient({
|
|
76
|
+
apiKey: process.env.WAZZAPI_API_KEY,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const response = await client.messages.send({
|
|
80
|
+
phone_number: "+6281234567890",
|
|
81
|
+
whatsapp_account_id: "your-whatsapp-account-id",
|
|
82
|
+
content: "Hello from WazzAPI!",
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
console.log(response.message_id, response.status);
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## API shape
|
|
89
|
+
|
|
90
|
+
The main client exposes four primary resources:
|
|
91
|
+
|
|
92
|
+
- `client.contacts`
|
|
93
|
+
- `client.groups`
|
|
94
|
+
- `client.messages`
|
|
95
|
+
- `client.templates`
|
|
96
|
+
|
|
97
|
+
Preferred TypeScript method names use camelCase:
|
|
98
|
+
|
|
99
|
+
- `client.contacts.listGroups()`
|
|
100
|
+
- `client.groups.getParticipants()`
|
|
101
|
+
- `client.messages.sendImage()`
|
|
102
|
+
- `client.templates.builtinVariables()`
|
|
103
|
+
|
|
104
|
+
Snake_case aliases are also available:
|
|
105
|
+
|
|
106
|
+
- `client.contacts.list_groups()`
|
|
107
|
+
- `client.groups.get_participants()`
|
|
108
|
+
- `client.messages.send_image()`
|
|
109
|
+
- `client.templates.builtin_variables()`
|
|
110
|
+
|
|
111
|
+
## Error handling
|
|
112
|
+
|
|
113
|
+
When the API returns a non-success response, the SDK throws `WazzapiAPIError`.
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
import { WazzapiAPIError, WazzapiClient } from "@wazzapi/wazzapi";
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
const client = new WazzapiClient({ apiKey: process.env.WAZZAPI_API_KEY });
|
|
120
|
+
await client.messages.get("missing-message-id");
|
|
121
|
+
} catch (error) {
|
|
122
|
+
if (error instanceof WazzapiAPIError) {
|
|
123
|
+
console.error(error.statusCode);
|
|
124
|
+
console.error(error.message);
|
|
125
|
+
console.error(error.details);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Webhook verification
|
|
131
|
+
|
|
132
|
+
Use `WebhookHandler` to verify the raw request body against `X-Wazzapi-Signature` before parsing JSON.
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
import { WebhookHandler } from "@wazzapi/wazzapi";
|
|
136
|
+
|
|
137
|
+
const handler = new WebhookHandler(process.env.WAZZAPI_WEBHOOK_SECRET || "");
|
|
138
|
+
const event = handler.verifyAndParse(rawBody, request.headers);
|
|
139
|
+
|
|
140
|
+
console.log(event.event_type);
|
|
141
|
+
console.log(event.data);
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
WazzAPI webhook headers:
|
|
145
|
+
|
|
146
|
+
- `X-Wazzapi-Signature`
|
|
147
|
+
- `X-Wazzapi-Event`
|
|
148
|
+
- `X-Wazzapi-Event-ID`
|
|
149
|
+
|
|
150
|
+
Supported webhook event families:
|
|
151
|
+
|
|
152
|
+
- message events: `message.received`, `message.sent`, `message.delivered`, `message.read`, `message.failed`
|
|
153
|
+
- device events: `device.connected`, `device.disconnected`
|
|
154
|
+
|
|
155
|
+
## Media downloads
|
|
156
|
+
|
|
157
|
+
Use `downloadMedia()` to retrieve and decrypt WhatsApp media payloads.
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
import { downloadMedia } from "@wazzapi/wazzapi";
|
|
161
|
+
|
|
162
|
+
const file = await downloadMedia(mediaUrl, mediaKey, mimeType, {
|
|
163
|
+
file_name: "invoice.pdf",
|
|
164
|
+
file_sha256: expectedPlainSha256,
|
|
165
|
+
file_enc_sha256: expectedEncryptedSha256,
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
console.log(file.file_name, file.file_size);
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Examples
|
|
172
|
+
|
|
173
|
+
### Standard examples
|
|
174
|
+
|
|
175
|
+
- `examples/list-contacts.ts`
|
|
176
|
+
- `examples/send-message.ts`
|
|
177
|
+
- `examples/create-template.ts`
|
|
178
|
+
- `examples/preview-template.ts`
|
|
179
|
+
- `examples/verify-webhook.ts`
|
|
180
|
+
|
|
181
|
+
### Advanced examples
|
|
182
|
+
|
|
183
|
+
- `advanced-examples/custom-fetch.ts` — custom fetch injection for logging and telemetry
|
|
184
|
+
- `advanced-examples/download-media.ts` — encrypted media download and verification
|
|
185
|
+
- `advanced-examples/http-webhook-server.ts` — minimal Node HTTP webhook receiver
|
|
186
|
+
|
|
187
|
+
## Documentation
|
|
188
|
+
|
|
189
|
+
Topic-based documentation is available in `docs/`:
|
|
190
|
+
|
|
191
|
+
- `docs/README.md`
|
|
192
|
+
- `docs/authentication.md`
|
|
193
|
+
- `docs/client.md`
|
|
194
|
+
- `docs/messages.md`
|
|
195
|
+
- `docs/groups.md`
|
|
196
|
+
- `docs/contacts.md`
|
|
197
|
+
- `docs/templates.md`
|
|
198
|
+
- `docs/webhooks.md`
|
|
199
|
+
- `docs/media.md`
|
|
200
|
+
- `docs/errors.md`
|
|
201
|
+
|
|
202
|
+
Repository: <https://github.com/wazzapihq/wazzapi-node>
|
|
203
|
+
|
|
204
|
+
## Try it
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
bun run examples/list-contacts.ts
|
|
208
|
+
bun run examples/send-message.ts
|
|
209
|
+
bun run examples/create-template.ts
|
|
210
|
+
bun run examples/preview-template.ts
|
|
211
|
+
bun run examples/verify-webhook.ts
|
|
212
|
+
bun run advanced-examples/custom-fetch.ts
|
|
213
|
+
bun run advanced-examples/download-media.ts
|
|
214
|
+
bun run advanced-examples/http-webhook-server.ts
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Development
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
bun install
|
|
221
|
+
bun run typecheck
|
|
222
|
+
bun test
|
|
223
|
+
bun run build
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Package output
|
|
227
|
+
|
|
228
|
+
The build produces:
|
|
229
|
+
|
|
230
|
+
- `dist/index.js` — ESM bundle
|
|
231
|
+
- `dist/index.cjs` — CommonJS bundle
|
|
232
|
+
- `dist/index.d.ts` — TypeScript declarations
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { WazzapiClient } from "../src";
|
|
2
|
+
|
|
3
|
+
function requireEnv(name: string): string {
|
|
4
|
+
const value = process.env[name];
|
|
5
|
+
if (!value) {
|
|
6
|
+
throw new Error(`Missing required environment variable: ${name}`);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async function loggingFetch(
|
|
13
|
+
input: string | URL | Request,
|
|
14
|
+
init?: RequestInit,
|
|
15
|
+
): Promise<Response> {
|
|
16
|
+
let url: string;
|
|
17
|
+
|
|
18
|
+
if (typeof input === "string") {
|
|
19
|
+
url = input;
|
|
20
|
+
} else if (input instanceof URL) {
|
|
21
|
+
url = input.toString();
|
|
22
|
+
} else {
|
|
23
|
+
url = input.url;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
console.log(`[wazzapi] ${init?.method ?? "GET"} ${url}`);
|
|
27
|
+
return fetch(input, init);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const client = new WazzapiClient({
|
|
31
|
+
apiKey: requireEnv("WAZZAPI_API_KEY"),
|
|
32
|
+
fetch: loggingFetch,
|
|
33
|
+
timeout: 15000,
|
|
34
|
+
headers: {
|
|
35
|
+
"X-SDK-Example": "advanced-custom-fetch",
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const stats = await client.messages.stats();
|
|
40
|
+
console.log(stats);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { downloadMedia } from "../src";
|
|
2
|
+
|
|
3
|
+
function requireEnv(name: string): string {
|
|
4
|
+
const value = process.env[name];
|
|
5
|
+
if (!value) {
|
|
6
|
+
throw new Error(`Missing required environment variable: ${name}`);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const result = await downloadMedia(
|
|
13
|
+
requireEnv("WAZZAPI_MEDIA_URL"),
|
|
14
|
+
requireEnv("WAZZAPI_MEDIA_KEY"),
|
|
15
|
+
process.env.WAZZAPI_MEDIA_MIMETYPE || "application/octet-stream",
|
|
16
|
+
{
|
|
17
|
+
file_name: process.env.WAZZAPI_MEDIA_FILE_NAME || "media.bin",
|
|
18
|
+
file_sha256: process.env.WAZZAPI_MEDIA_SHA256 || undefined,
|
|
19
|
+
file_enc_sha256: process.env.WAZZAPI_MEDIA_ENC_SHA256 || undefined,
|
|
20
|
+
},
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
console.log({
|
|
24
|
+
file_name: result.file_name,
|
|
25
|
+
file_size: result.file_size,
|
|
26
|
+
mimetype: result.mimetype,
|
|
27
|
+
});
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
|
|
3
|
+
import { Buffer } from "node:buffer";
|
|
4
|
+
import { createServer, type IncomingMessage } from "node:http";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
EVENT_HEADER,
|
|
8
|
+
EVENT_ID_HEADER,
|
|
9
|
+
SIGNATURE_HEADER,
|
|
10
|
+
WebhookHandler,
|
|
11
|
+
} from "../src";
|
|
12
|
+
|
|
13
|
+
function requireEnv(name: string): string {
|
|
14
|
+
const value = process.env[name];
|
|
15
|
+
if (!value) {
|
|
16
|
+
throw new Error(`Missing required environment variable: ${name}`);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function readRequestBody(request: IncomingMessage): Promise<Buffer> {
|
|
23
|
+
return new Promise((resolve, reject) => {
|
|
24
|
+
const chunks: Buffer[] = [];
|
|
25
|
+
|
|
26
|
+
request.on("data", (chunk: Buffer | string) => {
|
|
27
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
28
|
+
});
|
|
29
|
+
request.on("end", () => resolve(Buffer.concat(chunks)));
|
|
30
|
+
request.on("error", reject);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const handler = new WebhookHandler(requireEnv("WAZZAPI_WEBHOOK_SECRET"));
|
|
35
|
+
const port = Number(process.env.PORT || 3000);
|
|
36
|
+
|
|
37
|
+
const server = createServer(async (request, response) => {
|
|
38
|
+
if (request.method !== "POST" || request.url !== "/webhooks/wazzapi") {
|
|
39
|
+
response.statusCode = 404;
|
|
40
|
+
response.end("Not Found");
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
const rawBody = await readRequestBody(request);
|
|
46
|
+
const headers = {
|
|
47
|
+
[SIGNATURE_HEADER]: request.headers[
|
|
48
|
+
SIGNATURE_HEADER.toLowerCase()
|
|
49
|
+
] as string,
|
|
50
|
+
[EVENT_HEADER]: request.headers[EVENT_HEADER.toLowerCase()] as string,
|
|
51
|
+
[EVENT_ID_HEADER]: request.headers[
|
|
52
|
+
EVENT_ID_HEADER.toLowerCase()
|
|
53
|
+
] as string,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const event = handler.verifyAndParse(rawBody, headers);
|
|
57
|
+
console.log(`received ${event.event_type}`);
|
|
58
|
+
console.log(event.data);
|
|
59
|
+
|
|
60
|
+
response.statusCode = 200;
|
|
61
|
+
response.setHeader("content-type", "application/json");
|
|
62
|
+
response.end(JSON.stringify({ ok: true }));
|
|
63
|
+
} catch (error) {
|
|
64
|
+
console.error(error);
|
|
65
|
+
response.statusCode = 400;
|
|
66
|
+
response.setHeader("content-type", "application/json");
|
|
67
|
+
response.end(
|
|
68
|
+
JSON.stringify({
|
|
69
|
+
ok: false,
|
|
70
|
+
error: error instanceof Error ? error.message : "unknown error",
|
|
71
|
+
}),
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
server.listen(port, () => {
|
|
77
|
+
console.log(
|
|
78
|
+
`Webhook server listening on http://localhost:${port}/webhooks/wazzapi`,
|
|
79
|
+
);
|
|
80
|
+
});
|