TypeScript SDK for the waxum WhatsApp REST API gateway.
- Types are generated from the server's OpenAPI spec with openapi-typescript into
src/generated.ts. - A small hand-written client (
src/client.ts) wraps the core resources: sessions, session tags, messages, webhooks, and the live events tail. - Requires Node.js 18+ (uses global
fetch). No runtime dependencies.
The server exposes its OpenAPI document, unauthenticated, at:
GET http://localhost:3451/api-docs/openapi.json
(Swagger UI lives at /swagger-ui.)
npm install
npm run generate # from a running server on the default port
npm run generate -- --url http://host:3451
npm run generate -- --file ./openapi.json # from a saved spec fileEnvironment variables WAXUM_SPEC_URL and WAXUM_SPEC_FILE work as well. If
the URL fetch fails and an openapi.json sits next to this package.json, it
is used as a fallback.
A repo-level shortcut exists at the repo root:
./gen-sdk.sh # same as: npm run generate
./gen-sdk.sh --file openapi.jsonimport { WaxumClient } from '@waxum/sdk';
const client = new WaxumClient('http://localhost:3451', process.env.WAXUM_TOKEN!);
// Sessions
const created = await client.createSession({ session_id: 'shop' });
const sessions = await client.listSessions();
const status = await client.getSessionStatus('shop');
const qr = await client.getQrCode('shop');
// Tags
await client.addSessionTag('shop', 'production');
const tags = await client.listSessionTags('shop');
// Messages (all send payloads accept an optional `send_at` RFC 3339
// timestamp; with a future send_at the message is scheduled and the
// response carries schedule_id + status "pending" instead of message_id)
await client.sendText('shop', { to: '6281234567890', text: 'hello from the SDK' });
await client.sendImage('shop', {
to: '6281234567890',
image: { url: 'https://example.com/cat.jpg' },
caption: 'cat',
send_at: '2026-07-22T09:00:00Z',
});
// Scheduled messages
const pending = await client.listScheduled('shop', { status: 'pending' });
await client.cancelScheduled('shop', 'b3f1c2a4-1234-4cde-9f00-abcdef123456');
const fleetScheduled = await client.listAllScheduled({ status: 'pending' });
// Blasts (queued bulk sends to many recipients)
const blast = await client.createBlast('shop', {
endpoint: 'text', // send endpoint key: text, image, cta-url, ...
body: { text: 'promo this week' }, // payload of that endpoint's request struct
recipients: ['6281234567890', '6281234567891@s.whatsapp.net'],
delay_ms: 1000,
});
const jobs = await client.listBlasts('shop', { status: 'running' });
const job = await client.getBlast('shop', blast.job_id);
const recipients = await client.listBlastRecipients('shop', blast.job_id, { status: 'failed', limit: 50 });
await client.retryBlast('shop', blast.job_id);
await client.cancelBlast('shop', blast.job_id);
const fleetBlasts = await client.listAllBlasts();
// Webhooks
await client.registerWebhook('shop', {
url: 'https://example.com/hook',
events: ['message', 'session.status'],
});
const hooks = await client.listWebhooks('shop');
// Live events tail (Server-Sent Events, fetch-based reader;
// replays up to 50 recent matching events, then streams new ones)
for await (const ev of client.tailEvents({ session: 'shop' })) {
console.log(ev.event, JSON.parse(ev.data));
}All request/response shapes come from the generated OpenAPI types
(components['schemas'][...]), so editor autocomplete reflects the server
models. Endpoints that are not part of the OpenAPI document (session tags)
use small hand-written types.
Every send payload carries an optional send_at (RFC 3339 timestamp). All
send methods return the unified SendResponse schema: status is sent
with message_id/timestamp for immediate sends, or pending with
schedule_id when a future send_at was supplied. Scheduled rows are
managed through listScheduled / cancelScheduled / listAllScheduled.
| Resource | Methods |
|---|---|
| Sessions | createSession, listSessions, getSession, deleteSession, getSessionStatus, getQrCode, connectSession, pairSession, disconnectSession, getDeviceInfo |
| Tags | listSessionTags, replaceSessionTags, addSessionTag, removeSessionTag, listAllTags |
| Messages | sendText, sendImage, sendVideo, sendAudio, sendDocument, sendSticker, sendLocation, sendContact, sendPoll, sendButtons, sendList, sendInteractive, sendCtaUrl, sendQuickReply, editMessage, sendReaction, revokeMessage, markAsRead, forwardMessage, sendPinMessage |
| Scheduled | listScheduled, cancelScheduled, listAllScheduled |
| Blasts | createBlast, listBlasts, getBlast, listBlastRecipients, cancelBlast, retryBlast, listAllBlasts |
| Webhooks | listWebhooks, registerWebhook, unregisterWebhook, reenableWebhook |
| Events | tailEvents (SSE async generator) |
- Browser
EventSourcecannot set theAuthorizationheader and the events tail endpoint requires a bearer token, sotailEvents()is the supported way to consume the stream. - Group, contact, presence, chatstate, media, MEX, and operations endpoints
are not wrapped by dedicated methods yet; call them through the generated
pathstypes plusfetch, or extendWaxumClient.
| Script | Purpose |
|---|---|
npm run generate |
Regenerate src/generated.ts from the OpenAPI spec |
npm run typecheck |
tsc --noEmit |
npm run build |
Emit dist/ (ESM + declarations) |