Send a WhatsApp message
POSThttps://api.9bits.net/whatsapp/ng/v1/sendwhatsapp
Sends a single WhatsApp message to one recipient.
Request
Section titled “Request”| Field | Type | Required | Description |
|---|---|---|---|
to | string | ✅ | Recipient MSISDN in international format. |
message_type | string | — | template or text. Inferred if omitted — see below. |
template_name | string | — | The Meta-approved template. Required for template. |
language | string | — | Template language code, e.g. en. |
params | array | — | Values for the template’s {{1}}, {{2}}… placeholders, in order. |
header_media_url | string | — | Media URL for a template with a media header. |
text | string | — | Free-form body. Only valid for text, inside an open window. |
wa_account_id | integer | — | Which sender to send from. Defaults to your account default. |
Send a template
Section titled “Send a template”The only way to start a conversation.
curl -X POST https://api.9bits.net/whatsapp/ng/v1/sendwhatsapp \ -H "Authorization: Bearer $NINEBITS_WA_KEY" \ -H "Content-Type: application/json" \ -d '{ "to": "2348020000000", "message_type": "template", "template_name": "order_shipped", "language": "en", "params": ["Jane", "AB123"] }'const res = await fetch('https://api.9bits.net/whatsapp/ng/v1/sendwhatsapp', { method: 'POST', headers: { Authorization: `Bearer ${process.env.NINEBITS_WA_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ to: '2348020000000', message_type: 'template', template_name: 'order_shipped', language: 'en', params: ['Jane', 'AB123'], // order matters — {{1}}, {{2}} }),});
const msg = await res.json();if (!res.ok) throw new Error(msg.error);
console.log(msg.message_id, msg.category, msg.cost);import os, requests
res = requests.post( "https://api.9bits.net/whatsapp/ng/v1/sendwhatsapp", headers={"Authorization": f"Bearer {os.environ['NINEBITS_WA_KEY']}"}, json={ "to": "2348020000000", "message_type": "template", "template_name": "order_shipped", "language": "en", "params": ["Jane", "AB123"], }, timeout=10,)res.raise_for_status()print(res.json()["message_id"])Template with a media header
Section titled “Template with a media header”{ "to": "2348020000000", "message_type": "template", "template_name": "receipt_with_logo", "language": "en", "params": ["Jane", "12500.00"], "header_media_url": "https://cdn.example.com/img/receipt-header.png"}header_media_url must be publicly reachable — we fetch it when the message is
dispatched.
Send free-form text
Section titled “Send free-form text”Only works inside an open 24-hour window, i.e. after the customer has messaged you.
{ "to": "2348020000000", "message_type": "text", "text": "Thanks Jane — your refund is on its way."}Outside a window this is rejected. If you’re not certain the window is open, send a template instead.
Response
Section titled “Response”{ "message_id": "wamid.HBgNMjM0ODAyMDAwMDAwMBUCABEYEjZBNUQ2", "status": "sent", "cost": 32.5, "currency": "NGN", "category": "utility", "sender": "2349000000000"}| Field | Meaning |
|---|---|
message_id | WhatsApp’s wamid.…. Store it — delivery webhooks reference it. |
status | Dispatch status. |
cost / currency | What this message cost you. |
category | Meta’s billing category — utility, marketing, authentication, service. Set by the template. Marketing is the expensive one. |
sender | The WhatsApp number it went out from. |
Errors
Section titled “Errors”{ "error": "recipient 'to' is required" }| Status | Cause |
|---|---|
400 | Missing to, or a text message sent outside an open 24-hour window. |
401 | Missing or invalid API key. |
402 | Insufficient balance. |