WhatsApp Business
Send and receive WhatsApp messages through the official WhatsApp Business Platform (Cloud API) — templates, the 24-hour customer service window, media, and interactive messages
Blooio connects to the official WhatsApp Business Platform (Cloud API) so you can message your customers on WhatsApp from the same multi-channel API you already use for iMessage, SMS, and RCS. Onboarding uses Meta's Embedded Signup, so your customers connect their own WhatsApp Business Account (WABA) and phone number in a few clicks — nothing to hand-enter.
Note
WhatsApp Business is a v4 channel (
channel_type: "whatsapp_business"), served byapi.blooio.com/v4. It is a separate channel from peer-to-peer WhatsApp (coming later) and shares no data with it.
Overview
The WhatsApp Business integration lets you:
- Send template messages to start conversations (the only messages allowed outside the 24-hour window).
- Send free-form text, media (image / video / audio / document), and interactive (reply buttons, list, CTA URL) messages inside the customer service window.
- Receive inbound messages and delivery/read receipts as
message.*webhook events. - Track the full
sent → delivered → readlifecycle, mapped from Meta's status webhook.
Note
Blooio relays directly to Meta and does not queue, pace, or retry WhatsApp messages. Meta's messaging limits, throughput, and errors are surfaced straight back to you (see Limitations & rate limits).
When to use WhatsApp Business
| Use case | Why WhatsApp Business |
|---|---|
| International audiences | WhatsApp is the dominant messaging app across most of the world |
| Notifications & reminders | Approved utility templates deliver order, appointment, and shipping updates |
| Marketing opt-ins | Approved marketing templates reach opted-in users with rich content |
| Two-way support | Free-form replies for 24 hours after each inbound customer message |
WhatsApp complements Blooio's iMessage (rich 1:1 in the US) and Twilio SMS (broadcast scale). Choose the channel per audience and message type.
Onboarding (Embedded Signup)
Connect WhatsApp from the Blooio dashboard Integrations → WhatsApp Business → Connect. This launches Meta's Embedded Signup, where your customer:
- Logs in with Facebook and selects (or creates) their WhatsApp Business Account.
- Selects (or adds) the business phone number to use.
- Grants Blooio the
whatsapp_business_managementandwhatsapp_business_messagingpermissions.
Blooio then exchanges the returned code for a business access token, subscribes the app to the WABA's webhooks, registers the phone number, and provisions a whatsapp_business channel. The WABA id and phone number are pulled dynamically from the customer's Meta account — there is nothing to type in.
Warning
In the WhatsApp Business Platform's Tech Provider model, the onboarded business adds their own payment method to their WABA (Meta bills the business directly). Blooio only relays messages on their behalf.
Once connected, the channel's display_address is the connected phone number, and you send to it just like any other Blooio number.
Sending
Send with the v4 POST /v4/messages endpoint. Set to to the recipient in E.164 format and from to your connected WhatsApp number (or pass channel_type: "whatsapp_business" to let Blooio resolve the channel).
Text
Free-form text is allowed inside the 24-hour customer service window (see below).
cURL
curl -X POST 'https://api.blooio.com/v4/messages' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"to": "+15551234567",
"from": "+15559876543",
"text": "Thanks for reaching out! How can we help?"
}'Try itNode.js
await fetch('https://api.blooio.com/v4/messages', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.BLOOIO_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
to: '+15551234567',
from: '+15559876543',
text: 'Thanks for reaching out! How can we help?'
})
})Python
requests.post('https://api.blooio.com/v4/messages',
headers={
'Authorization': f"Bearer {os.environ['BLOOIO_API_KEY']}",
'Content-Type': 'application/json'
},
json={
'to': '+15551234567',
'from': '+15559876543',
'text': 'Thanks for reaching out! How can we help?'
}
)Media
Attach an image, video, audio file, or document by public HTTPS URL. An optional caption travels in text (images, videos, and documents support captions).
cURL
curl -X POST 'https://api.blooio.com/v4/messages' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"to": "+15551234567",
"from": "+15559876543",
"text": "Your receipt is attached.",
"attachments": [
{ "url": "https://example.com/receipt.pdf", "fileName": "receipt.pdf" }
]
}'Try itNode.js
await fetch('https://api.blooio.com/v4/messages', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.BLOOIO_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
to: '+15551234567',
from: '+15559876543',
text: 'Your receipt is attached.',
attachments: [
{ url: 'https://example.com/receipt.pdf', fileName: 'receipt.pdf' }
]
})
})Python
requests.post('https://api.blooio.com/v4/messages',
headers={
'Authorization': f"Bearer {os.environ['BLOOIO_API_KEY']}",
'Content-Type': 'application/json'
},
json={
'to': '+15551234567',
'from': '+15559876543',
'text': 'Your receipt is attached.',
'attachments': [
{ 'url': 'https://example.com/receipt.pdf', 'fileName': 'receipt.pdf' }
]
}
)Blooio infers the WhatsApp media type from the file extension. To force it, add "media_type": "image" | "video" | "audio" | "document" alongside attachments.
Template
Templates are the only messages allowed outside the 24-hour window. Reference an approved template by name and language, and pass positional body variables in variables.
cURL
curl -X POST 'https://api.blooio.com/v4/messages' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"to": "+15551234567",
"from": "+15559876543",
"template": {
"name": "order_confirmation",
"language": "en_US",
"variables": ["Ada", "#A1234"]
}
}'Try itNode.js
await fetch('https://api.blooio.com/v4/messages', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.BLOOIO_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
to: '+15551234567',
from: '+15559876543',
template: {
name: 'order_confirmation',
language: 'en_US',
variables: ['Ada', '#A1234']
}
})
})Python
requests.post('https://api.blooio.com/v4/messages',
headers={
'Authorization': f"Bearer {os.environ['BLOOIO_API_KEY']}",
'Content-Type': 'application/json'
},
json={
'to': '+15551234567',
'from': '+15559876543',
'template': {
'name': 'order_confirmation',
'language': 'en_US',
'variables': ['Ada', '#A1234']
}
}
)Note
Create and sync templates from the dashboard (or
POST /organizations/:id/integrations/whatsapp/:channelId/templates). Templates must be approved by Meta before they can be sent. For advanced templates (header media, buttons), pass a raw Cloud APIcomponentsarray instead ofvariables.
Interactive
Inside the window, send reply buttons (up to 3), a list (up to 10 rows total), or a call-to-action URL button.
Reply buttons
curl -X POST 'https://api.blooio.com/v4/messages' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"to": "+15551234567",
"from": "+15559876543",
"interactive": {
"kind": "button",
"body": "Did this resolve your issue?",
"buttons": [
{ "id": "yes", "title": "Yes, thanks" },
{ "id": "no", "title": "Still stuck" }
]
}
}'Try itList
curl -X POST 'https://api.blooio.com/v4/messages' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"to": "+15551234567",
"from": "+15559876543",
"interactive": {
"kind": "list",
"body": "Pick a time that works for you",
"button": "View times",
"sections": [
{
"title": "Morning",
"rows": [
{ "id": "9am", "title": "9:00 AM" },
{ "id": "10am", "title": "10:00 AM" }
]
}
]
}
}'Try itCTA URL
curl -X POST 'https://api.blooio.com/v4/messages' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"to": "+15551234567",
"from": "+15559876543",
"interactive": {
"kind": "cta_url",
"body": "Your order has shipped.",
"display_text": "Track package",
"url": "https://example.com/track/A1234"
}
}'Try itCustomer service window & templates
WhatsApp only allows free-form messages within a rolling 24-hour customer service window that opens (and resets) each time the customer messages you. Outside that window you may send only approved template messages.
Blooio enforces this locally, before relaying to Meta, so you fail fast with a clear error instead of burning your messaging quota on a rejected send:
| Situation | Result |
|---|---|
| Inside the window | Any content type is allowed |
| Outside the window, non-template content | 422 template_required_outside_customer_service_window |
| Template not approved on the WABA | 422 template_not_approved |
Note
A template send is allowed at any time (in or out of the window), as long as the template is approved. Sending a template re-engages a customer whose window has closed.
Receiving
Inbound WhatsApp messages are delivered to your registered webhooks as message.received events, with channel_type: "whatsapp_business" and protocol: "whatsapp":
{
"id": "evt_019fd421-b020-7a63-8f8b-152ea9c99333",
"type": "message.received",
"created_at": 1706640000000,
"organization_id": "org_abc123",
"data": {
"message_id": "msg_019fd421-af64-7040-aeae-3e8df24a8e89",
"chat_id": "chat_019fd421-af64-7040-aeae-3e8df24a8e89",
"channel_id": "ch_019f959b-ff70-7b1e-9b42-e457bf848fd7",
"channel_type": "whatsapp_business",
"kind": "received",
"direction": "inbound",
"status": "received",
"protocol": "whatsapp",
"message_type": "text",
"text": "Hi, is my order on its way?",
"provider_message_id": "wamid.HBgLMTU1NTEyMzQ1NjcVAgAR...",
"sender": "+15551234567",
"contact": { "identifier": "+15551234567" },
"attachments": []
}
}WhatsApp-specific fields:
provider_message_idis the WhatsApp message id (wamid).- Interactive replies carry the tapped option id in the message metadata (
interactive_reply_id). - Replies to a specific message carry the quoted message's wamid (
context_wamid). - Media messages re-host the file to a servable Blooio URL and appear under
attachments.
Each inbound message opens or resets the 24-hour customer service window for that chat.
Message status & webhook events
Outbound WhatsApp messages progress through the standard v4 lifecycle, mapped from Meta's status webhook and delivered as message.* events:
| Status | Event | Meaning |
|---|---|---|
sent |
message.sent |
Meta accepted the message (a wamid was issued) |
delivered |
message.delivered |
Delivered to the recipient's device |
read |
message.read |
The recipient opened the message |
failed |
message.failed |
Delivery failed — inspect error (see below) |
Status is forward-only: a late delivered never walks back a read. Reactions arrive as message.reaction events.
Limitations & rate limits
Blooio relays directly to Meta and does not queue or retry. Meta's limits apply as-is:
- Messaging limits (tiers) — cap the number of unique users you can open business-initiated (template) conversations with in a rolling 24 hours:
TIER_250→TIER_2K→TIER_10K→TIER_100K→TIER_UNLIMITED. Set at the business-portfolio level and shared across all numbers in it. In-window replies and user-initiated chats don't count. - Throughput — up to 80 messages/second per number by default, auto-upgrading toward 1,000 mps for high-volume, high-quality numbers. Exceeding it returns error
130429(retriable). - Pair rate limit — roughly 1 message every 6 seconds to the same user (error
131056, retriable). Batch consecutive lines to one user into a single message. - Content caps (enforced locally before send): text body ≤ 4,096; media caption ≤ 1,024; reply buttons ≤ 3 (title ≤ 20); list ≤ 10 sections / 10 rows total; hydrated template body ≤ 1,024.
- Media sizes: image 5 MB, video/audio 16 MB, document 100 MB, sticker 100 KB (static) / 500 KB (animated).
Warning
When Meta rejects a send synchronously, Blooio marks the message
failedand surfaces the reason. Retriable errors carryretriable: true— your application decides whether to resend; Blooio never buffers or auto-retries.
Best practices
- Lead with templates, continue free-form. Open with an approved template, then converse freely within the 24-hour window the customer's reply opens.
- Keep templates approved and synced. Sync templates from the dashboard so
template_not_approvednever surprises you at send time. - Monitor status events. Handle
message.delivered/message.read/message.failedto track deliverability, and watch quality signals in Meta Business Manager. - Respect the window. Check for
template_required_outside_customer_service_windowand fall back to a template (or another channel) when the window has closed. - Handle failures yourself. WhatsApp sends fail immediately with no Blooio retry — implement your own retry for
retriable: trueerrors.
Troubleshooting
template_required_outside_customer_service_window (422)
The 24-hour window has closed for this chat. Send an approved template to re-engage, or wait for the customer to message you again.
template_not_approved (422)
The template name / language you referenced isn't approved on this WABA. Create or sync the template and wait for Meta's approval (up to 24 hours).
130429 — throughput limit (retriable)
You're sending faster than the number's messages-per-second limit. Slow down and resend; capacity auto-upgrades for high-quality, high-volume numbers.
131047 — re-engagement required
Meta's version of the closed-window error, if a template send slips through. Send an approved template to re-open the conversation.
131048 / 131049 — quality / per-user marketing cap
131048 is a spam/quality restriction; 131049 means the user hit their cross-business marketing cap — wait at least 24 hours before retrying that user.
132005 — hydrated template body too long
Your template variables produced a body over 1,024 characters. Shorten the variable values or the template body.
100 / 131009 — invalid or malformed content
A payload/parameter was rejected. Check the recipient format (E.164), media URL/type, and template variable count.
Next steps
- Message fields reference (v4) — the full v4 message object, status, and protocol states
- Webhooks — receive
message.*events in real time - Twilio Integration — SMS/MMS via your own Twilio account