WhatsApp messaging
Connect a number, create approved templates, send messages, and track delivery — by hand or from your code.
This is the end-to-end guide to sending on WhatsApp with Darkel. It follows the natural order: connect a number, get a template approved, send, then track what happened.
How sending works
WhatsApp does not let businesses send arbitrary text out of the blue. To start a conversation you must use a template that Meta has reviewed and approved. Darkel sends are therefore always template-based — you pick an approved template and fill in its variables.
- You need a connected number to send from (your own, or a shared Darkel number).
- You need at least one approved template.
- You need a funded prepaid balance with WhatsApp enabled.
Template-only sending is a feature, not a limitation: an approved template delivers to your customer regardless of WhatsApp’s 24-hour reply window. You never have to worry about “the session expired”.
Connect a number
Open WhatsApp in the dashboard. You have two paths:
Option A — Bring your own number (recommended)
Messages arrive from your own verified business name and number, so customers see you rather than a number they do not recognise. You keep ownership of the WhatsApp Business Account, your template library is yours to author, and Meta bills you directly for conversations. Connect it in a few clicks through Meta’s secure Embedded Sign-up.
Start here if you can. Sending under your own business identity earns more trust, keeps your sender reputation in your hands, and lets you write your own templates without waiting on us.
Start the secure sign-up
Click “Connect WhatsApp”. This opens Meta’s official Embedded Sign-up in a popup.
Pick your business & number
Sign in to Facebook, choose (or create) your WhatsApp Business Account, and select the phone number to send from.
Finish
Meta hands the connection back to Darkel and we securely store the access it grants. Your verified business name and number then show in the dashboard.
Option B — Use a shared Darkel number
If connecting your own number is not practical yet — no WhatsApp Business Account, no verified business, or you simply want to send today — start on a Darkel-managed number instead. There is no Meta setup and no Meta billing to configure, and it is the default in sandbox. Each message is charged to your Darkel balance at Meta’s price for its type and the recipient’s country, converted to naira at Darkel’s published rate with no markup — see the price list. Templates on a shared number are curated by us rather than authored by you, and messages arrive from a Darkel number rather than your brand. You can move to your own number later without changing any code.
With your own number, Meta bills you directly for WhatsApp conversations — Darkel adds no per-message charge — and your access credentials are encrypted at rest — Darkel never exposes them.
Billing eligibility (own number)
If a message is accepted but never delivered, the most common cause is that your WhatsApp Business Account has no active payment method with Meta (Meta error 131042). Add a payment method to your WABA in Meta Business settings. See Delivery & errors.
Create & manage templates
A template is a reusable message with placeholders for the bits that change. Meta reviews each template before it can be used. There are three categories:
| Category | Use for | Who writes the text |
|---|---|---|
| Utility | Order updates, reminders, receipts | You |
| Marketing | Promotions, offers, announcements | You |
| Authentication | One-time passcodes (OTP) | Meta — you only supply the code |
Creating a template (your own number)
Name it
Use lowercase letters, numbers and underscores, e.g.
order_confirmation. The name is how you reference it when sending.Write the body with placeholders
Use
{{1}},{{2}}… where values vary, e.g. “Hi {{1}}, your order {{2}} is on its way.”Pick a category & language
Choose Utility, Marketing or Authentication and the language code (default
en_US).Submit for review
Meta typically approves within minutes to a few hours. Status shows as pending → approved (or rejected, with a reason).
Authentication templates
For OTPs, Meta supplies the wording (e.g. “{{1}} is your verification code”) and adds a copy-code button. You only choose an optional code-expiry time and, when sending, pass the code itself. You do not write the body.
Using a shared number?
Templates on a shared Darkel number are curated for you — browse the available ones in the dashboard. If you need a new template on a shared number, contact us. To author your own templates freely, connect your own number.
Moving to your own number? Templates do not come with you
An approved template lives on the WhatsApp account that owns it. When you connect your own number you create and submit your templates again on your own account, and they get their own approvals. A template you write there can differ from the shared one it replaces — so re-check the variables your send code passes, because a mismatch is rejected with 132000.
Send a message
Once you have an approved template, sending is the same idea everywhere: name the template, give the recipient, and supply the variable values via components.
From the dashboard
Go to WhatsApp → Send, pick a template, choose the recipient, fill in the variables, and send. Great for one-offs and for confirming a template works before you automate it.
From your code
/v1/whatsapp/messagesX-Api-KeySend a template message from the workspace that owns the key.
{
"to": "+2348012345678",
"template": {
"name": "order_confirmation",
"languageCode": "en_US",
"components": [
{
"type": "body",
"parameters": [
{ "type": "text", "text": "Ada" },
{ "type": "text", "text": "DK-1042" }
]
}
]
}
}| Field | Required | Notes |
|---|---|---|
to | Yes | Recipient in E.164 format, e.g. +2348012345678 |
template.name | Yes | Exact name of an approved template |
template.languageCode | No | Defaults to en_US; must match the template’s language |
template.components | Sometimes | Required if the template has variables; the order of parameters maps to {{1}}, {{2}} … |
Mapping placeholders
The first item in body parameters fills {{1}}, the second fills {{2}}, and so on. A template with no placeholders can be sent with no components at all.
Parameter limits & formatting
Every parameter value must be a single line: no line breaks, tabs, or 4 or more consecutive spaces. Authentication templates additionally cap each value (the code) at 15 characters — they are meant for short verification codes, not names or sentences. Other categories (Utility, Marketing) allow longer values, up to the 1024-character body limit. A value that breaks these rules is rejected with a 400 before it reaches WhatsApp — so put long content in a Utility/Marketing template, not an Authentication one.
| Template category | Max length per parameter |
|---|---|
| Authentication | 15 characters |
| Utility | Up to the 1024-char body limit |
| Marketing | Up to the 1024-char body limit |
Sending an OTP (authentication template)
Authentication templates carry a short verification code plus a Copy code button. You must send the code twice — once in the body and once in the button — or the Copy code button will not appear. Every parameter is capped at 15 characters.
Match your own template, not the example
A template belongs to the WhatsApp account it was created on. The first example below is Darkel’s shared otp_verification, whose body takes two variables. The moment you send on your own number, only the templates you created on your own WhatsApp account exist — the same name is still a different template, with whatever variables you gave it. Send more or fewer parameters than your template’s {{n}} placeholders and WhatsApp rejects it with 132000; a name or language that does not exist on your account is 132001. Check the exact shape under WhatsApp → Templates before you automate.
{
"to": "+2348012345678",
"template": {
"name": "otp_verification",
"languageCode": "en_US",
"components": [
{
"type": "body",
"parameters": [
{ "type": "text", "text": "399399" },
{ "type": "text", "text": "Acme Ltd" }
]
},
{
"type": "button",
"sub_type": "url",
"index": 0,
"parameters": [
{ "type": "text", "text": "399399" }
]
}
]
}
}{
"to": "+2348012345678",
"template": {
"name": "otp_verification",
"languageCode": "en_US",
"components": [
{
"type": "body",
"parameters": [
{ "type": "text", "text": "399399" }
]
},
{
"type": "button",
"sub_type": "url",
"index": 0,
"parameters": [
{ "type": "text", "text": "399399" }
]
}
]
}
}The Copy code button is required
The button component is not optional when your template has a Copy code button — omit it and the send is rejected (131008) or the button is dropped. Use sub_type: "url", a numeric index: 0 (a string index silently drops the button), and put the same code as the body. Drop the button component only if your own template genuinely has no button. Keep every value ≤ 15 characters.
Track delivery & replies
Every send returns a message record immediately, then progresses through statuses as WhatsApp reports back:
| Status | Meaning |
|---|---|
pending | Accepted by Darkel, being handed to WhatsApp |
sent | WhatsApp accepted it |
delivered | Reached the recipient’s device |
read | The recipient opened it |
failed | Delivery failed — the full price is refunded automatically |
- See the full history under WhatsApp → Messages in the dashboard, searchable by number, template or text.
- When a customer replies, the inbound message is captured and attributed to your workspace.
- Each message record has a
pricingobject — see API reference. Charges and refunds are in Billing & pricing. - Statuses, automatic refunds and Meta error codes are explained in Delivery & errors.
Testing in the sandbox
Create your sandbox
From the dashboard, spin up your free sandbox workspace. It comes with play money and a shared test number.
Use approved test recipients
Sandbox sends only reach numbers on the approved test list — the dashboard shows them, and the send screen offers them as choices. Ask us to add more if needed.
Send with a dk_test_ key
Create a
dk_test_key in the sandbox and send exactly as you would in production — same endpoint, same body. Only the key differs.Go live
When it works end-to-end, switch to your live workspace, connect/confirm your number, fund the balance, and swap in a
dk_live_key.