Node.js / TypeScript
Use the official SDK @whatstig/sdk (ESM, Node 18.17+, typed from the OpenAPI contract). A complete runnable example
lives in the repository at examples/node-typescript (src/reminder.ts shows invoice reminders with native
follow-ups: a reminder sequence, anchorAt, dedupeKey, rescheduling and cancelling).
npm install @whatstig/sdk
Client
import { WhatsTig, WhatsTigError } from '@whatstig/sdk';
const wt = new WhatsTig({
apiKey: process.env.WHATSTIG_API_KEY!, // server-side only
baseUrl: process.env.WHATSTIG_BASE_URL, // default https://api.whatstig.com
timeoutMs: 30_000,
maxRetries: 2, // network errors, 429, 502-504 on safe requests only
});
Instances
const instance =
(await wt.instances.findByExternalReference('tenant-101')) ??
(await wt.instances.create({ name: 'School A WhatsApp', externalReference: 'tenant-101' }, { idempotencyKey: 'create-tenant-101' }));
await wt.instances.connect(instance.id, { method: 'qr' });
const pairing = await wt.instances.qr(instance.id); // pairing.qrDataUrl → <img src=...>
const final = await wt.instances.waitForConnected(instance.id, 180_000);
Messages
const accepted = await wt.messages.send(
{ instanceId: instance.id, recipient: '923001234567', type: 'text', content: { text: 'Hello' }, clientReference: 'n-1' },
{ idempotencyKey: 'n-1' },
);
const msg = await wt.messages.get(accepted.id); // status: QUEUED | PROCESSING | SENT | DELIVERED | READ | FAILED | UNKNOWN
for await (const m of wt.messages.listAll({ status: 'FAILED' })) console.log(m.id, m.failure?.code);
// Media
const media = await wt.media.upload(await readFile('report.pdf'), 'report.pdf', 'application/pdf');
await wt.messages.send({ instanceId: instance.id, recipient: '923001234567', type: 'document', content: { mediaId: media.id, fileName: 'Report.pdf' } });
Errors
try {
await wt.messages.send(/* ... */);
} catch (err) {
if (err instanceof WhatsTigError) {
// err.status, err.code (e.g. INVALID_RECIPIENT), err.message, err.requestId, err.details, err.retryAfterSeconds
}
throw err;
}
Webhooks (Express)
import express from 'express';
import { verifyWebhook, WebhookVerificationError } from '@whatstig/sdk';
const app = express();
// Raw body is required for signature verification.
app.post('/whatstig/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
try {
const event = verifyWebhook(req.body, req.header('WhatsTIG-Signature'), process.env.WHATSTIG_WEBHOOK_SECRET!);
void handleEvent(event); // dedupe on event.id, process asynchronously
res.sendStatus(200);
} catch (err) {
res.sendStatus(err instanceof WebhookVerificationError ? 401 : 500);
}
});
Without the SDK, any HTTP client works; see Generic REST and the verification snippet in Webhooks.