Test mode and magic numbers
Keys prefixed blu_test_ are sandbox keys. Sends made with them never reach WhatsApp or any provider, never bill, and are flagged as test data. The sandbox simulates the full delivery lifecycle so your status handling and webhook code run against realistic events.
The simulated lifecycle
On a test key a message moves queued → sent → delivered, about one step every 5 seconds, and on to read for WhatsApp; SMS and email stop at delivered. The webhooks message.sent, message.delivered and message.failed fire as it moves; the simulated read fires none.
Each test webhook is signed with your endpoint secret, as live traffic is, and carries "test": true in its payload.
Message statuses
queued: accepted and waiting to send. Every send, live or test, starts here.sending: handed to the provider, whose answer is not back yet. A send still sending after 30 minutes is failed.sent: the provider accepted it.delivered: it reached the phone or the mailbox.read: the recipient read it, on a channel that reports reads (WhatsApp).failed: it could not be sent or delivered; the message says why.parked: held because the prepaid wallet ran out of credit; it is queued again after a top-up. Never on a test key.
Magic numbers
Deterministic recipients let you exercise every path your integration must handle:
| Number | Behaviour |
|---|---|
+27800000001 | Always delivers (any other number behaves the same way). |
+27800000002 | Always fails at the send step with recipient_unreachable and fires message.failed. |
+27800000003 | Delivers, then fires a simulated message.received reply so you can test inbound handling. |
Testing the failure path
// A new sandbox has no templates yet: send free-form text, and create the contact in the same call.
const msg = await bt.messages.send({
channel: "whatsapp",
to: { phone: "+27800000002", create: true, first_name: "Always Fails" },
body: "This one is meant to fail.",
});
// ~5 seconds later:
const failed = await bt.messages.get(msg.message_id);
console.log(failed.status); // "failed"
// and your webhook receives message.failed with "test": trueValidate-only requests
Independently of the key type, you can pass test_mode: true in a send body to validate auth, contact lookup, template variables, and opt-outs without creating anything at all — the safest very first call:
const check = await bt.messages.send({
test_mode: true,
channel: "whatsapp",
to: { phone: "+27821234567" },
template_id: "<template id>",
template_variables: { "1": "Sam" },
});
console.log(check.status); // "validated"
console.log(check.rendered_body_preview);Differences from live
- No provider calls, no Meta quality/tier effects, no billing.
- Timing is fixed (~5s per step); live WhatsApp delivery timing varies.
- Test rows are flagged
test_modein your workspace data.