A Raíz agent talks to your organization’s contacts, on phone calls (voice) or on WhatsApp and web chat (text). This guide creates a text agent with raiz.agents.create, then reads it, changes it and puts it on a channel.
Before you start
You need a credential for your organization that holds raiz:agents:write (see Authentication). The examples read an API key from ARBOL_API_KEY.
| Operation | Request | Scopes (any one) |
|---|---|---|
raiz.agents.create |
POST /v1/raiz/agents |
raiz:agents:write |
raiz.agents.get |
GET /v1/raiz/agents/{agentId} |
raiz:agents:read, raiz:agents:write |
raiz.agents.list |
GET /v1/raiz/agents |
raiz:agents:read, raiz:agents:write |
raiz.agents.update |
PATCH /v1/raiz/agents/{agentId} |
raiz:agents:write |
raiz.channels.update |
PATCH /v1/raiz/channels/{channelId} |
raiz:channels:write |
Each accepts an API key, a machine token or a person’s sign-in. An API key needs the scope among those chosen when it was created; a person’s token counts only as far as their roles grant it.
Create the agent
Only modality and name are required. Add instructions, language and timeZone so the agent knows its job and speaks in the right language and time zone:
curl https://api.getarbol.com/v1/raiz/agents \
--request POST \
--header "Authorization: Bearer $ARBOL_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"modality": "text",
"name": "Appointment reminders",
"instructions": "You remind patients of Example Clinic about upcoming appointments and confirm whether they will attend. You never give medical advice.",
"language": "es-CO",
"timeZone": "America/Bogota"
}'The body accepts only the fields its schema declares; any other field answers 400 INVALID_INPUT. The optional ones:
| Field | Meaning |
|---|---|
instructions |
What the agent does and how: its role, what it may and may not do, the facts it relies on. Up to 100,000 characters. |
language |
BCP 47 language tag, such as es-CO. |
timeZone |
IANA time zone, such as America/Bogota. |
firstMessage |
Voice agents: what the agent says when a call connects. Text agents open WhatsApp conversations with settings.greeting instead. |
status |
active or paused. A paused agent answers nothing and places no calls. |
knowledgeDocumentIds |
Up to 100 ready Knowledge documents to consult, from raiz.knowledge.list. |
integrationTools |
Up to 200 connectionId and tool pairs: the tools of your integrations the agent may call. |
integrationSkills |
Text agents: up to 32 connectionId and skill pairs that a connection publishes. |
skills |
Up to 32 text-only procedures, 256 KiB in total. |
settings |
How the agent behaves. Text and voice settings apply only to agents of that modality. |
description |
Up to 2,000 characters. |
A successful call answers 200 with the agent in data. The response below is abridged: the full object also carries status, ready, settings, skills, integrationSkills and toolCount.
{
"success": true,
"data": {
"id": "agt_01jd8x5k2m7q9r3t6v8w0y4z1b",
"name": "Appointment reminders",
"modality": "text",
"version": 1,
"instructions": "You remind patients of Example Clinic about upcoming appointments and confirm whether they will attend. You never give medical advice.",
"language": "es-CO",
"timeZone": "America/Bogota",
"firstMessage": null,
"description": null,
"synced": true,
"syncErrorCode": null,
"channelCount": 0,
"channels": [],
"knowledgeDocumentIds": [],
"integrationTools": [],
"createdAt": "2026-10-30T15:04:05Z",
"updatedAt": "2026-10-30T15:04:05Z"
},
"error": null,
"metadata": { "requestId": "3f6c2a8e-1b4d-4e7a-9c0f-5d2e8b1a7c64" }
}Keep data.id: every other operation on the agent takes it as agentId. Two fields say where the agent stands:
ready: whether it can hold conversations. It must beactiveand have instructions, and a voice agent must also be published for calls.synced: whether calls already use the current version. Voice agents are published in the background, so check it after each change;syncErrorCodesays why publishing failed. It is alwaystruefor text agents.
Read it back
raiz.agents.get takes agentId in the URL path and answers the agent’s complete setup:
curl "https://api.getarbol.com/v1/raiz/agents/agt_01jd8x5k2m7q9r3t6v8w0y4z1b" \
--header "Authorization: Bearer $ARBOL_API_KEY"To find agents, raiz.agents.list filters by status, modality and q (the name, ignoring accents and case), newest first:
curl "https://api.getarbol.com/v1/raiz/agents?modality=text&q=reminders" \
--header "Authorization: Bearer $ARBOL_API_KEY"The agents are in data.data, 25 per page by default; pass data.pageInfo.nextCursor as cursor for the next page. See Pagination.
Update it
Put agentId in the URL path and send the fields to change and, as expectedVersion, the version you read:
curl https://api.getarbol.com/v1/raiz/agents/agt_01jd8x5k2m7q9r3t6v8w0y4z1b \
--request PATCH \
--header "Authorization: Bearer $ARBOL_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"expectedVersion": 1,
"instructions": "You remind patients of Example Clinic about upcoming appointments, confirm whether they will attend and pass reschedule requests to the team. You never give medical advice."
}'- Fields you leave out stay as they are, and
nullclears a field that accepts it. settings,integrationTools,integrationSkills,skillsandknowledgeDocumentIdsreplace the whole value. Read the agent first and send the complete new value; settings you leave out return to their default.- With
expectedVersion, the change applies only if nobody changed the agent since you read it. Otherwise it answers409 VERSION_CONFLICT: read the agent again and reapply your change. "status": "paused"stops the agent from answering and calling.modalitychanges only while the agent has no channels and no published voice line.
Put it on a channel
Assign the agent to a WhatsApp number, phone number or web chat widget so it answers there. Find the channel with raiz.channels.list, then send its id and the agent’s to raiz.channels.update:
{
"channelId": "chn_01jd8x6b3c4d5e6f7g8h9j0k1m",
"agentId": "agt_01jd8x5k2m7q9r3t6v8w0y4z1b"
}The agent’s modality must fit the channel: text for WhatsApp and web chat, voice for phone numbers.
Errors
| Status | Code | What to do |
|---|---|---|
| 400 | INVALID_INPUT |
Fix the fields in error.data.issues; each path is a JSON Pointer to a refused field. |
| 400 | AGENT_SKILLS_INVALID |
Skills need a text agent, unique names and resource paths, nonempty instructions and at most 256 KiB in total. |
| 403 | FORBIDDEN |
The credential lacks the scope the operation needs. |
| 409 | VERSION_CONFLICT |
Read the agent again and reapply your change. |
| 409 | AGENT_MODALITY_LOCKED |
The agent has channels or a published voice line. Create a new agent instead. |
| 409 | EVAL_GATE_UNMET |
The agent has settings.evalGate on: send evalRunId, a completed evaluation run of exactly this content in which every case passed. |
| 422 | INTEGRATION_TOOL_UNAVAILABLE, INTEGRATION_SKILL_UNAVAILABLE |
A tool or skill isn’t on that connection, or Raíz can’t run it. Check account.connections.list. |
| 422 | KNOWLEDGE_DOCUMENT_UNAVAILABLE |
A Knowledge document doesn’t exist in this organization. |
| 422 | AGENT_SETTINGS_INVALID |
A setting doesn’t apply to the agent’s modality, or two settings contradict each other. |
| 502 | OUTCOME_UNKNOWN |
The change may have been applied: read the agent before you repeat it. |
Every failure carries error.code, error.message, error.retryable and metadata.requestId. See Responses and errors.