Official WhatsApp & one API for both channels
Connect a number through Meta's WhatsApp Business Platform — your verified business name, message templates, no QR code to keep alive — and send on it, or on your QR-code number, through one endpoint. Sozuri picks the right number for every message.
- Connect an official number
- Keep using the WhatsApp Business app
- The 24-hour window and templates
- Send a message
- Which number a message leaves from
- Response
- List your channels
- Templates
- Receiving messages
- Delivery & read receipts
- Rate limits
- Pricing
- Error responses
Connect an official number
In the dashboard open Project → WhatsApp → Official WhatsApp (Meta) and press Connect with Meta. Meta's own sign-in window opens: log in with Facebook, choose or create your business portfolio and WhatsApp Business Account, and verify the phone number by SMS or voice call. Sozuri finishes the setup and the number appears on the page, ready to send.
You need admin access to the business portfolio, and a payment method on the WhatsApp Business Account — Meta bills its own fees to you directly (see Pricing).
Keep using the WhatsApp Business app
A number already on the WhatsApp Business app can join the official platform without leaving the app: you keep chatting from your phone, and Sozuri sends from the same number. Press Connect my WhatsApp Business app number, choose to connect your existing app account in Meta's window, then follow Settings → Account → Business Platform in the app.
- You need WhatsApp Business app 2.24.17 or later.
- Your contacts and the last six months of 1:1 chats can be brought across — only in the first 24 hours, and only once. Sozuri asks for them the moment you connect; chats you imported appear in your inbox but never trigger an automation or your webhook.
- Messages you send from the app are free at Meta and are never charged by Sozuri. A reply you type on your phone pauses the AI agent for that conversation, exactly like a reply from the inbox.
- Such a number sends at most 20 messages a second. Group chats are not synchronised, and broadcast lists in the app become read-only.
- A number on the official platform can't also be linked on the QR-code channel — Sozuri ignores the QR copy of every message, so nothing is answered twice.
The 24-hour window and templates
On the official channel you may send any message to a customer who has written to that number in the last 24 hours. Outside that window only an approved template can be sent — it is how a conversation is started or restarted. Create templates under Official WhatsApp → Templates (or with the API); Meta reviews each one. A free-form send outside the window is refused before it reaches Meta, with the time the window closed.
Send a message
POST /api/v1/whatsapp/messages works for both WhatsApp channels. It accepts the
official channel's typed shape, and the exact body of /v1/whatsapp/send —
an integration written for the QR channel works unchanged.
| Field | Required | Type | Description |
|---|---|---|---|
| project | Yes | String | The project name that owns the API key. |
| to | Yes | String | International format, country code first, no + or leading 0 (254700000000). A QR-channel JID (...@s.whatsapp.net, ...@g.us) or an official-channel user id (KE.1234...) also works — each exists on one channel only. |
| type | For the typed shape | String | text, image, video, audio, document, sticker, location, interactive, reaction or template, plus an object of the same name: "text": {"body": "…"} (or just "text": "…"), "image": {"link": "https://…", "caption": "…"}, "template": {"name": "order_ready", "language": "en", "params": {"body": ["Amina"]}}. |
| text, imageUrl, … | For the QR shape | — | The /v1/whatsapp/send fields: text plus at most one media, location or contact field. |
| channel | No | String | qr or meta to choose the channel yourself. |
| from | No | String | One of your numbers, when you have several — it also decides the channel. |
| replyTo | No | String | The id of the message you are answering (official channel). |
A template (starts a conversation)
curl -X POST https://sozuri.net/api/v1/whatsapp/messages \
-H "Authorization: Bearer $SOZURI_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "project": "your_project_name", "to": "254700000000", "type": "template",
"template": { "name": "order_ready", "language": "en", "params": { "body": ["Amina", "A-1042"] } } }'
A reply (inside the 24-hour window)
curl -X POST https://sozuri.net/api/v1/whatsapp/messages \
-H "Authorization: Bearer $SOZURI_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "project": "your_project_name", "to": "254700000000", "text": "Your order is on its way" }'
Which number a message leaves from
With both channels connected, the first rule that applies decides:
channelorfrom, when you send them.- An address that exists on one channel only (a JID on QR, a user id on the official channel).
- A template → the official channel, the only one with templates.
- A reply → the number the customer last wrote to in the past 24 hours. Automated answers (the AI agent, keyword rules, workflows) always leave from the number the message arrived on.
- Your project's default, set on the Official WhatsApp page.
- Otherwise the QR channel — a free-form message to somebody who has not written would be refused on the official one.
The response says which channel carried the message and why (channel, routed).
Response
{
"status": "accepted",
"channel": "meta",
"routed": "template",
"message": {
"id": "wamid.HBgLMjU0NzAw...",
"to": "254700000000",
"from": "254711000000",
"type": "template",
"status": "pending"
}
}
message.id is the key delivery and read receipts arrive under. On the
official channel an accepted message is pending: sent, delivered and
read follow as Meta reports them.
List your channels
GET /api/v1/whatsapp/channels?project=your_project_name returns what the project has:
{
"default": null,
"channels": [
{ "channel": "qr", "available": true, "status": "connected", "number": "254700000001" },
{ "channel": "meta", "available": true, "numbers": [
{ "number": "254711000000", "phoneNumberId": "1098...", "verifiedName": "Duka Bora", "connected": true,
"quality": "GREEN", "coexistence": false } ] }
]
}
Templates
GET /api/v1/whatsapp/templates lists your templates and their review status;
POST /api/v1/whatsapp/templates submits one for Meta's review (name,
language, category of marketing, utility or
authentication, and its body). Only an APPROVED template can be sent.
Receiving messages
Set Your webhook for this number on the Official WhatsApp page. Every message the number receives is POSTed to it — the same envelope as the QR channel, plus the fields only this channel has:
{
"event": "message.received",
"channel": "meta",
"from": "254722000000",
"to": "254711000000",
"chatId": "254722000000",
"profileName": "Amina",
"message": { "id": "wamid.HBgL...", "type": "text", "text": "Is my order ready?", "fromMe": false },
"timestamp": "2026-09-27T09:06:40+00:00"
}
to is which of your numbers was written to. A customer who uses a WhatsApp username
may arrive with fromUserId (e.g. KE.1234…) — reply to from through this
API and it reaches them either way. Media arrives with a media object once Sozuri holds a copy of
the file (its url), and a reply carries message.replyTo. Requests are signed exactly
like every Sozuri callback — X-Sozuri-Signature, secret under
Manage API → Callback URLs → Webhook security.
Delivery & read receipts
Receipts always update the dashboard and the inbox. With status callbacks enabled (ask support), they are also POSTed to the number's webhook, once per status:
{
"event": "message.status",
"channel": "meta",
"messageId": "wamid.HBgL...",
"status": "delivered",
"to": "254722000000",
"from": "254711000000",
"timestamp": "2026-09-27T09:07:02+00:00"
}
A failed message carries reason, in words, e.g. undeliverable.
Rate limits
Each channel keeps its own per-project limit, and /v1/whatsapp/messages draws on the same
allowance as the channel-specific endpoint: a message routed to QR counts against the QR channel's (deliberately
small) limit, one routed to the official channel against the official one. Separately, Meta lets a number send
80 messages a second — 20 for a number shared with the WhatsApp Business app — and a burst beyond that is
answered 429 throughput_exceeded before it reaches Meta. Both are safe to retry.
Pricing
Meta bills its fee to your WhatsApp Business Account's payment method, per delivered message, by category: marketing, utility and authentication templates, and — from 1 October 2026 — service replies (each number has 1,000 free service messages a month) and utility templates sent inside the 24-hour window. Messages inside a free entry point window (a customer who reached you from a click-to-WhatsApp ad) are free for 72 hours. Sozuri's own per-message fee is taken from your project balance when Meta reports the message delivered, at the rate for the category Meta reports; nothing is charged for a message that was not delivered.
Error responses
Errors are { "error": { "code", "message", "status", "channel"? } }:
| Status | Code | What to do |
|---|---|---|
| 409 | not_connected, channel_unavailable | The channel you need is not connected on this project. |
| 422 | window_closed | Send an approved template; error.window says when the window closed. |
| 422 | template_not_found, template_not_approved, template_parameters | Check the template's name, language and values. |
| 422 | unsupported_on_qr, unsupported_on_meta | That kind of message exists on the other channel only. |
| 422 | address_not_on_channel | The channel or from you named cannot reach that address: a …@s.whatsapp.net, @lid or @g.us address exists only on the QR channel, a user id (KE.…) only on the official one. Leave both out and the address decides. |
| 422 | from_required | The project has several official numbers: say which in from. |
| 402 | insufficient_balance | Top up the project. |
| 429 | rate_limited, RATE_LIMITED, throughput_exceeded | Slow down and retry. |
| 503 | channel_off, channel_reconnecting | Temporary — retry shortly. |