TypeScript SDK
@blueticked/sdk is the official client for the Blueticked API. It has zero dependencies and runs on Node 18+, serverless functions, and edge runtimes. It wraps /api/v1 with typed methods, automatic idempotency, retries, and a single error type you can catch.
Install
npm install @blueticked/sdkZero dependencies, MIT licensed, ESM and CommonJS, Node 18+. Not using TypeScript or JavaScript? Generate a typed client from our public OpenAPI document instead — it works today in any language and needs no API key to read:
npx openapi-typescript https://app.blueticked.com/api/v1/openapi.json -o ./src/blueticked.d.tsQuickstart
Construct the client with an API key, then send an approved WhatsApp template. Keep the key in an environment variable — never inline it in source.
import { Blueticked } from "@blueticked/sdk";
const bt = new Blueticked({ apiKey: process.env.BLUETICKED_API_KEY! });
const message = await bt.messages.send({
channel: "whatsapp",
to: { phone: "+27821234567" },
template_id: "<an approved template id>",
template_variables: { "1": "Sam" },
});
console.log(message.status); // "queued"What the client handles for you
- Idempotency. Every
POSTgets an auto-generatedIdempotency-Key, so a retried create never duplicates a send. Pass your own key to any method to control it yourself. - Retries with backoff.
429and5xxresponses are retried with exponential backoff and jitter, honouringretry-afterwhen present. Tune withmaxRetries(default2; set0to disable) — see Rate limits and retries. - Request timeouts. Each request is bounded by
timeoutMs(default30000); a timed-out request rejects rather than hanging. - Typed errors. Any non-2xx response throws a
BluetickedErrorexposingcode,status, andmessage(plusrequestIdfor support) — see Error codes.
const bt = new Blueticked({
apiKey: process.env.BLUETICKED_API_KEY!,
maxRetries: 4, // default 2; set 0 to handle retries yourself
timeoutMs: 15000, // default 30000
});Handling errors
Catch BluetickedError to branch on a stable code instead of parsing messages:
import { Blueticked, BluetickedError } from "@blueticked/sdk";
try {
await bt.messages.send({
channel: "whatsapp",
to: { phone: "+27821234567" },
template_id: "<template id>",
});
} catch (err) {
if (err instanceof BluetickedError) {
console.error(err.code); // e.g. "validation_failed"
console.error(err.status); // e.g. 422
console.error(err.message); // human-readable
console.error(err.requestId); // include when contacting support
} else {
throw err;
}
}Test mode
A key prefixed blu_test_ puts the client in sandbox mode — bt.isTestMode is true, and sends never reach WhatsApp, never bill, and are flagged as test data. Use the magic numbers to exercise delivery, failure, and inbound-reply paths deterministically.
const bt = new Blueticked({ apiKey: "blu_test_..." });
if (bt.isTestMode) {
// send to +27800000002 to force a message.failed, etc.
}Verifying webhooks
Verify signed deliveries with constructEvent. Always pass the raw request body and the x-blueticked-signature header — it throws on a bad signature, so return 401 in your catch. This matches the Webhooks and signing guide.
export async function POST(req: Request) {
const rawBody = await req.text(); // do not re-serialize
try {
const event = await bt.webhooks.constructEvent(
rawBody,
req.headers.get("x-blueticked-signature") ?? "",
process.env.BLUETICKED_WEBHOOK_SECRET!,
);
if (event.event === "message.delivered") {
// update your order, mark the statement sent, etc.
}
return new Response("ok");
} catch {
return new Response("bad signature", { status: 401 });
}
}Resources
The client exposes a typed resource per API area: messages, contacts, campaigns, templates, flows, conversations, channels, email, suppression, groups, wallet, events, integrations, and webhooks. Each follows the same shape (list, get, create, and so on) and is fully typed.
The SDK surface is expanding — for the complete, up-to-date method reference and every field, see the package README on npm. Prefer raw HTTP? Every method maps to a documented endpoint in the OpenAPI spec.