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

Terminal
npm install @blueticked/sdk

Zero 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:

Terminal
npx openapi-typescript https://app.blueticked.com/api/v1/openapi.json   -o ./src/blueticked.d.ts

Quickstart

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.

send.ts
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 POST gets an auto-generated Idempotency-Key, so a retried create never duplicates a send. Pass your own key to any method to control it yourself.
  • Retries with backoff. 429 and 5xx responses are retried with exponential backoff and jitter, honouring retry-after when present. Tune with maxRetries (default 2; set 0 to disable) — see Rate limits and retries.
  • Request timeouts. Each request is bounded by timeoutMs (default 30000); a timed-out request rejects rather than hanging.
  • Typed errors. Any non-2xx response throws a BluetickedError exposing code, status, and message (plus requestId for support) — see Error codes.
client.ts
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:

catch.ts
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.

test-mode.ts
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.

app/api/blueticked/route.ts (Next.js)
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.