Quickstart
Send your first WhatsApp message in under ten minutes. You will use a test key, so you do not need a WhatsApp Business Account, a Meta app, or a connected phone number — the sandbox simulates the entire delivery lifecycle, including webhooks.
1. Get a test API key
Sign up at app.blueticked.com, then go to Developers → API keys and create a key. Test keys start with blu_test_; live keys with blu_live_. Creating a key requires two-step verification on your account — enable it first if you skipped it during sign-up.
2. Generate a client (optional)
npx openapi-typescript https://app.blueticked.com/api/v1/openapi.json -o ./src/blueticked.d.tsOur OpenAPI 3.1 document is public and needs no key, so you can generate a typed client in any language today. The examples below use plain fetch so they run anywhere with no dependencies — every call is a normal HTTPS request with Authorization: Bearer blu_test_.... See the OpenAPI spec for the full surface.
3. Create a contact and send
On a test key this runs on a brand-new workspace — you do not need a connected channel, an approved template, or a business id.
const API = "https://app.blueticked.com/api/v1";
const auth = {
Authorization: `Bearer ${process.env.BLUETICKED_TEST_KEY}`,
"Content-Type": "application/json",
};
// +27800000001 is a magic sandbox number: it always delivers.
await fetch(`${API}/contacts`, {
method: "POST",
headers: auth,
body: JSON.stringify({ phone: "+27800000001", first_name: "Sam" }),
});
const res = await fetch(`${API}/messages`, {
method: "POST",
headers: { ...auth, "Idempotency-Key": crypto.randomUUID() },
body: JSON.stringify({
channel: "whatsapp",
to: { phone: "+27800000001" },
body: "Hello from the Blueticked sandbox.",
}),
});
const message = await res.json();
console.log(message.status); // "queued"Two more sandbox numbers let you build error handling and inbound before you go live: +27800000002 fails at the send step with recipient_unreachable, and +27800000003 delivers and then fires a simulated inbound reply — the same webhook a real customer reply produces.
4. Watch it deliver
The sandbox advances the message every few seconds: queued, then sent, then delivered, then read. (SMS and email stop at delivered — neither emits a read receipt live, so the sandbox does not invent one.) Poll it, or better, receive webhooks:
const status = await fetch(`${API}/messages/${message.message_id}`, {
headers: auth,
}).then((r) => r.json());
console.log(status.status); // "delivered" a few seconds later5. Receive webhooks
Add a webhook subscription under Developers → Webhooks in the dashboard, then verify and handle deliveries — test-mode events carry "test": true:
import { createHmac, timingSafeEqual } from "node:crypto";
export async function POST(req: Request) {
const raw = await req.text(); // raw body — never re-serialize before verifying
const signature = req.headers.get("x-blueticked-signature") ?? "";
// Subscription webhooks sign the raw body alone.
const expected =
"sha256=" +
createHmac("sha256", process.env.BLUETICKED_WEBHOOK_SECRET!)
.update(raw)
.digest("hex");
const a = Buffer.from(signature);
const b = Buffer.from(expected);
if (a.length !== b.length || !timingSafeEqual(a, b)) {
return new Response("bad signature", { status: 401 });
}
const event = JSON.parse(raw);
if (event.event === "message.delivered") {
// update your order, mark the statement sent, etc.
}
return new Response("ok"); // 2xx within 15s, or we retry
}One thing worth knowing: webhooks you subscribe to here sign the raw body alone, but form post-submit actions and saved integrations sign HMAC(`${timestamp}.${rawBody}`) and send an extra x-blueticked-timestamp header for replay protection. Both use the same header name for the signature, so verify against the scheme for the surface you subscribed to.
Going live
- Connect your WhatsApp number in minutes via Embedded Signup (Onboarding → Connect WhatsApp). Blueticked is a verified Meta Tech Provider.
- Submit a template for approval — see Templates and approval.
- Swap
blu_test_forblu_live_. Nothing else changes.