Register a sender, get templates approved by Meta, and message contacts inside and outside the 24-hour window.
Jelliu agents answer and start conversations on WhatsApp Business. The channel runs on the WhatsApp Business Platform through Twilio, with one sender (a business phone number) per workspace. Everything a contact writes to that number is routed to one of your agents, and everything you send goes through the same compliance, opt-out and quota checks as the rest of the platform.
This page covers the API surface: senders, templates, sending, what happens to inbound messages, and the limits that apply.
How it works
Three rules shape every integration:
- Nothing is sent without an
ONLINEsender. Sends from a workspace whose number is still being approved, or is offline, are refused with an explanation. - Meta’s 24-hour customer-care window decides the message form. Freeform text is allowed only if the contact wrote to your number in the last 24 hours. Outside that window only an approved template can be sent.
- An opt-out is final. When a contact asks to stop, Jelliu suppresses the number and sends nothing more, not even a confirmation.
Senders
A sender is the WhatsApp Business phone number your workspace messages from. Replies are sent from the line the contact last wrote to, when that line is still online; otherwise from your most recently updated online sender.
Endpoints
Every response wraps the result in data. DELETE returns 204 with no body.
Sender lifecycle
Twilio does not push sender status changes, so Jelliu polls them about every two minutes and also re-checks senders that are already ONLINE, because Meta can take a number offline for quality reasons. Call POST /api/whatsapp-senders/{senderId}/refresh to re-read the status immediately.
status_reason is written for the person who has to fix it and may be in Spanish. For example, a number still registered on another WhatsApp account reports: Este número sigue registrado en otra cuenta de WhatsApp. Elimina esa cuenta en el teléfono (Ajustes → Cuenta → Eliminar cuenta) o migra el número, espera unos minutos y vuelve a intentarlo.
The sender object
Register a number
E.164 format: +, a country digit 1 to 9, then up to 14 more digits.
sms or voice: how the one-time code is delivered to the number.
Your own WhatsApp Business Account ID, up to 64 characters. Omit it to register under the account connected to the platform.
Meta’s ID for the number inside that account, up to 64 characters. Recorded for support only.
1 to 120 characters.
Up to 139 characters.
A URL, up to 256 characters.
An email address, up to 128 characters.
Up to 256 characters.
Up to 256 characters.
One of Meta’s fixed business categories. GET /api/whatsapp-senders/verticals returns the list: Automotive, Beauty, Spa and Salon, Clothing and Apparel, Education, Entertainment, Event Planning and Service, Finance and Banking, Food and Grocery, Public Service, Hotel and Lodging, Medical and Health, Non-profit, Professional Services, Shopping and Retail, Travel and Transportation, Restaurant, Other.
A URL, up to 512 characters.
Do not delete an ONLINE sender to “test reconnecting”. Removing it at the provider does not remove the number from the WhatsApp Business Account, and registering it again can be blocked by Meta, for example when two-step verification is enabled on the number in WhatsApp Manager.
Claim an existing sender
If a number is already registered as a WhatsApp sender with the provider, POST /api/whatsapp-senders/adopt with { "phoneNumber": "+573001234567" } binds it to your workspace. GET /api/whatsapp-senders/adoptable lists candidates. The number must already be an active number of your workspace; otherwise the claim is refused with 403: +573001234567 is not one of this account's numbers, so it cannot be claimed as a WhatsApp sender.
Update and remove
PATCH /api/whatsapp-senders/{senderId} accepts any of the profile fields above (at least one). It fails with 400 while the sender is not yet registered with the provider.
DELETE /api/whatsapp-senders/{senderId} removes the sender at the provider first. If the provider refuses, nothing is changed and you can retry.
Templates
A template is a message Meta has approved in advance. It is the only way to write to someone who has not messaged your number in the last 24 hours, and it also works inside the window.
Endpoints
Categories
Approval states
Approval results are polled from the provider about every two minutes, including for templates already approved, because Meta can pause or disable them later. POST /api/whatsapp-templates/{templateId}/refresh re-reads the state on demand.
The template object
Variables
Placeholders are written {{1}}, {{2}} and so on. variables declares one label per placeholder, so a body with two placeholders needs exactly two labels. Before a template is created, edited or submitted, Jelliu checks the body against the rules Meta rejects on, so you find out in seconds rather than after days of review:
- numbering starts at
{{1}}and has no gaps; - the body is not only a placeholder;
- two placeholders are never adjacent (
{{1}} {{2}}); - the body does not start or end with a placeholder;
- the number of labels matches the number of placeholders.
A body that breaks a rule is refused with 400 and code VALIDATION_FAILED, and the message names the rule, in Spanish. For example:
Matches ^[a-z0-9_]{1,120}$.
1 to 1024 characters.
2 to 16 characters.
AUTHENTICATION, MARKETING or UTILITY.
Up to 20 labels, each 1 to 50 characters.
Up to 200 characters.
Create, submit and preview a template
Preview it
Preview renders the body with sample values. It never contacts the provider and costs nothing. Missing values appear as [label], and warnings lists anything Meta would reject.
variables accepts an array (index 0 fills {{1}}) or an object keyed by position ({"1": "Ana"}), with up to 20 values of 400 characters each. With GET, pass them as the variables query parameter.
Test sends
POST /api/whatsapp-templates/{templateId}/test-send sends an approved template to any E.164 number so you can see it on a real phone, without creating a contact:
It returns 202 with messageSid, status, to, from and rendered.
A test send is a real, billed WhatsApp message: there is no simulation mode. Test sends are capped at 10 per workspace and 3 per template per UTC day, and they also count against the workspace’s daily WhatsApp cap. Units are refunded when the provider rejects the send.
Deleting templates
DELETE /api/whatsapp-templates/{templateId} removes the template at the provider and in Jelliu. A deleted template’s name stays reserved for that language: creating another template with the same name and language fails with 409.
Sending messages
Two endpoints send to a contact. Both take a contactId (the contact must have a WhatsApp number and belong to your workspace), both accept a write key, and both run the same checks.
POST /api/whatsapp/send
The contact to message.
Freeform text, 1 to 4096 characters. Allowed only inside the 24-hour window.
An approved template. Works inside and outside the window. When both are set, the template wins.
Values for the template’s placeholders: an ordered array, or an object keyed by position such as {"1": "Ana"}.
Provide message or templateId. Neither returns 400: Provide either a message or a templateId.
POST /api/whatsapp/reach
The contact to message.
1 to 4096 characters. Sent as written when the window is open.
2 to 10 characters. The template language to fall back on when the window is closed.
- Window open:
messageis sent as freeform text anddata.formisfreeform. - Window closed: your newest approved template in
languageis sent instead anddata.formistemplate. Your text is not delivered; the template opens the conversation, and once the contact replies the window is open again. - Window closed and no approved template in that language: nothing is sent, and the call fails with
422 NO_TEMPLATE_AVAILABLE.
note is written for an AI agent to relay to the contact. Branch on form in your own code.
Checks before every send
Both endpoints run these checks in order. A failure stops the send before any quota is used.
- The contact exists in your workspace and has a WhatsApp number.
- Compliance. The number is checked against your compliance rules: allowed contact hours for the contact’s country, blocked prefixes, the suppression list, do-not-call status, and the daily and total attempt limits.
- Opt-out. A contact with status
dncor an opt-out date cannot be messaged. - Message form. A template must exist, be
approvedand be ready at the provider; freeform requires the 24-hour window. - Daily cap. One unit of the workspace’s daily WhatsApp cap is consumed. It is refunded if the send then fails.
- Sender. An
ONLINEsender must exist.
Unlike email, WhatsApp sends respect the allowed contact hours of your compliance configuration. By default that is 08:00 to 20:00 in the contact’s country (for Colombia, America/Bogota). If your workspace has a timezone set, the hours are evaluated in that timezone instead. A send outside the window fails with 423 COMPLIANCE_BLOCKED, for example Outside allowed call hours (08:00-20:00 America/Bogota).
The attempt limits count calls to the contact. A contact who already received the maximum number of calls today (3 by default) cannot be messaged on WhatsApp until the next day either.
WhatsApp campaigns
A campaign with channel set to whatsapp writes first to every contact with the campaign’s approved template. Set whatsappTemplateId, whatsappTemplateVariables (literal values) and whatsappTemplateVariableMap (per-contact values such as {"1": "contact.first_name"}) on the campaign. Activation is refused if the template is not approved or a placeholder has no value source. Sends are paced at roughly one every 1.5 seconds per worker, and the last 20% of the daily cap (at least 25 messages) is reserved for replies so a campaign cannot leave your agent unable to answer. See Campaigns.
Inbound messages
When a contact writes to one of your numbers, Jelliu:
- Routes by the receiving number. The number must belong to exactly one workspace with an
ONLINEsender or an active phone number. Messages to numbers that are unknown, or claimed by more than one workspace, are dropped. - Checks for an opt-out before anything else (see below).
- Finds the contact. It matches the sender’s number against contacts’ WhatsApp and phone numbers, preferring a contact in an active campaign, then a paused one, then a completed one. People who are not in any campaign are welcome: Jelliu creates a contact for them, unless the number is on the suppression list.
- Picks the agent. The campaign’s agent if it serves WhatsApp; otherwise the agent bound to the receiving number; otherwise the workspace’s oldest agent that serves WhatsApp.
- Opens the 24-hour window for that contact.
- Generates and sends the reply in the background. If the agent has a response delay or human pacing configured, the reply waits, and several messages sent in a row are answered together.
Voice notes are transcribed and answered; the reply to a voice note includes a spoken version when it is short enough (600 characters or less), and the text is always sent too. Photos and PDFs sent with or without a caption reach the agent together with the caption.
Inbound conversations and their messages are available through Conversations.
AI replies on WhatsApp draw from your plan’s monthly allowance of AI messages. When it is used up, the agent stops replying and the workspace receives an in-app notification. See Limits.
Opt-out
A message is treated as an opt-out when the whole message is one of these keywords (case, extra spaces and trailing punctuation are ignored):
stop, stopall, stop all, cancel, unsubscribe, quit, end, baja, cancelar, darme de baja, dar de baja, no molestar
Longer phrasings such as “no me vuelvas a escribir” are also detected. Keywords inside a sentence are not: “quiero cancelar mi cita” is a request to reschedule, and the agent answers it. Voice notes are checked after transcription.
When an opt-out is detected, Jelliu:
- sets every contact in your workspace with that number to
dncand records the date and the matched keyword; - adds the number to the workspace’s suppression list, which survives deleting and re-importing the contact;
- sends nothing back, not even a confirmation.
From then on, every send to that number fails with 403 CONTACT_OPTED_OUT or 423 COMPLIANCE_BLOCKED, and inbound messages from it are not answered. See Compliance to review or lift a suppression.
Delivery statuses
Jelliu subscribes to the provider’s delivery callbacks for every message it sends and records the latest status per message. Statuses only move forward: a late failed never overwrites a message already recorded as delivered or read.
The status in a send response is the status at the moment of sending, usually queued.
Per-message delivery statuses are not currently exposed through the API or outbound webhooks.
Errors
Send errors from /api/whatsapp/send and /api/whatsapp/reach use the standard envelope with a WhatsApp-specific code:
Sender and template endpoints return the generic codes from Errors: VALIDATION_FAILED (400, or 409 for duplicates such as +573001234567 is already registered as a WhatsApp sender.), FORBIDDEN, NOT_FOUND and RATE_LIMIT_EXCEEDED. A test send over its daily cap returns 429 RATE_LIMIT_EXCEEDED with a Spanish message such as Ya enviaste 3 pruebas de esta plantilla hoy. Cada prueba es un mensaje real que WhatsApp factura; intentalo manana.
Limits
Monthly AI message allowance
AI replies on WhatsApp, email, web chat, Instagram and Messenger share one monthly allowance per plan:
When the allowance is used up, or the workspace has no active plan, AI replies stop with 403 BILLING_ERROR, for example Llegaste al límite mensual de mensajes de IA (1200 mensajes del plan starter). Sube de plan en Ajustes → Plan. Messages you send yourself through /api/whatsapp/send are limited by the daily cap, not by this allowance. See Billing and usage.

