Raíz can reach out as well as answer. A campaign has a voice agent call a list of people within the hours you allow, and it can call again those who didn’t answer. On WhatsApp, a conversation your organization starts must open with a message template WhatsApp has approved. And when something changes for a while, such as a closed day or a service that isn’t available, a bulletin tells your agents, without touching their instructions.
Call campaigns
raiz.campaigns.create prepares a campaign for a voice agent, with up to 10,000 recipients. Creating it calls nobody: the campaign stays queued until it’s started. The call isn’t idempotent.
curl https://api.getarbol.com/v1/raiz/campaigns \
--request POST \
--header "Authorization: Bearer $ARBOL_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"name": "Appointment reminders, November",
"agentId": "agt_01jd8xq4r5s6t7v8w9x0y1z2a3",
"instructions": "Remind {{contact_given_name}} of their appointment on {{appointment_date}} and ask whether they will attend.",
"contactHours": [{ "days": ["MO", "TU", "WE", "TH", "FR"], "from": "08:00", "to": "18:00" }],
"timeZone": "America/Bogota",
"maxAttempts": 3,
"retryAfterMinutes": 120,
"recipients": [
{ "address": "+12025550143", "variables": { "appointment_date": "November 12" } }
]
}'| Field | What it does |
|---|---|
agentId |
The voice agent that calls. One that can’t take calls yet answers 409 VOICE_AGENT_NOT_READY: it must be active, have instructions and be published for calls. |
recipients |
Each a phone address in E.164, unique in the campaign, with an optional contactId, variables, and a firstMessage and instructions for that call. |
firstMessage, instructions |
What the agent says first on every call, and what these calls are about, added to the agent’s instructions. |
contactHours, timeZone |
When calls may start, in the campaign’s time zone, the organization’s by default. Empty: any time. |
scheduledStartAt, scheduledEndAt |
No call starts before or after these instants. |
maxAttempts, retryAfterMinutes, retryOn |
Calls per recipient, retries included (1 to 10, default 1); the wait before a retry (default 60 minutes); and which results earn one: no_answer (the default) and failure. |
channelId |
The voice line calls leave from. By default, the agent’s own outbound line. |
The texts of the agent and the campaign can use {{name}} variables, filled from each recipient’s variables. Raíz always provides contact_name, contact_given_name, contact_id, contact_phone, conversation_id and bulletins (the bulletins in force), and a recipient’s values never replace them. A recipient’s contact is the one it names, or else the contact that owns its number, created when there is none.
Follow and change a campaign
A campaign’s status is queued (not started, or its start is scheduled), running (calling the recipients that are due), paused (no new call starts; calls in progress finish), completed (nobody is left to call), cancelled or failed. Its progress counts its recipients and how many are pending, inProgress, completed or failed, and how many succeeded: their latest call’s analysis judged it successful.
raiz.campaigns.get with expand=recipients adds each recipient’s status, attempts, next attempt and latest call, whose conversationId leads to its transcript. A recipient that failed says why in errorCode: NO_ANSWER or CALL_FAILED after its last attempt, or CONTACT_SUPPRESSED when a do-not-contact rule forbids the number. The campaign’s calls are also in raiz.conversations.list with campaignId.
raiz.campaigns.update changes a campaign; fields you leave out stay. "paused": true pauses a started campaign and false resumes it, with the same checks as starting; on a campaign that never started, it answers 409 INVALID_STATE. Before the start, recipients is the complete list, matched by address; once started, it only adds, so you can send a long list in batches. The agent changes only before the start, and a completed campaign accepts only a new name and metadata. Your organization places at most settings.channels.maxConcurrentOutboundCalls campaign calls at once (5 by default).
WhatsApp templates
WhatsApp lets a business start a conversation, or write to someone who hasn’t written in the last 24 hours, only with a message template it approved. Templates belong to the WhatsApp Business Account of each number, so both template operations take a WhatsApp channelId.
raiz.templates.list reads a channel’s templates live from WhatsApp, newest first, and filters them by status: approved, pending or rejected. sendable says whether Raíz can send one: approved, with variables only in the body and, if it has a media header, a document, image or video. parameterCount is how many body values a send needs.
raiz.templates.create submits a template for WhatsApp’s review:
{
"channelId": "chn_01jd8x6b3c4d5e6f7g8h9j0k1m",
"name": "appointment_reminder",
"language": "en_US",
"category": "utility",
"body": {
"text": "Hello {{1}}, this is a reminder of your appointment on {{2}} at Example Clinic.",
"examples": ["Ana", "November 12"]
}
}The name takes lowercase letters, digits and _, and the language WhatsApp’s code, such as es, es_MX or en_US. category is utility for messages about something the person asked for, such as appointments, or marketing for promotions. The body has up to 1,024 characters with variables {{1}}, {{2}} and so on, and one examples value per variable. A header (a fixed text, or a document, image or video with a sample file of up to 5 MiB), a footer and up to 10 buttons are optional. The template stays pending until WhatsApp approves or rejects it, usually within minutes; WhatsApp may change its category, and rejectedReason says why it was rejected.
You also choose approved templates for a WhatsApp contact profile, which opens each conversation with one, and for a number’s outside-hours notice.
Bulletins
A bulletin tells your agents about something happening for a while: a service that isn’t available, no appointments at a site for some days, a closed day, a promotion. Agents apply it on calls, WhatsApp and web chat until it ends. It isn’t sent to anyone; agents take it into account when they talk to people. Your team may call bulletins novedades or avisos.
raiz.bulletins.create takes the text, up to 1,000 characters, written as you would tell your agents, with what they should offer instead. Add an agentId for one agent, or leave it out for every agent. startsAt is now by default, and without endsAt the bulletin lasts until it’s deleted. In this example, Example Clinic works in America/Bogota, so its days end at 05:00 UTC:
{
"text": "The North site is closed from 24 to 26 November. Offer appointments at the South site instead.",
"endsAt": "2026-11-27T05:00:00Z"
}Agents apply a bulletin from their next reply or call once it starts, and no agent reads it before. For agents to know ahead, so they book nothing on a closed day, start it now and write the dates in the text, as above. A bulletin’s status is scheduled, active or ended. An organization can have 30 bulletins in force or scheduled (409 BULLETIN_LIMIT_REACHED), and one that would end before it starts, or would already be over, answers 422 BULLETIN_PERIOD_INVALID.
raiz.bulletins.list lists scheduled and active bulletins, or ended ones with status=ended, by agentId or by text with q. raiz.bulletins.update changes one; to end it now, set endsAt to the current instant (a scheduled one is deleted instead). raiz.bulletins.delete deletes one that was a mistake, and the change history keeps who deleted it. Bulletins use the agents scopes: raiz:agents:write to post, change or delete one.