API reference

AI Agents

Policy-bound LLM agent personas for WhatsApp automation — CRUD, completions, prompt-version history, and response logs.

Beta. Published under the ai_agents capability marked Beta in /openapi.json. The route set and response fields may still expand; existing fields stay stable.
Provider API keys are encrypted at rest and never returned. AIAgentResponse exposes only api_key_suffix. Cross-organization lookups return 404, never 403.

Create

POST/v1/ai-agentsIdempotency-Key required

Request

FieldTypeNotes
namerequiredstring
len 1..120
descriptionstring
len 0..500
providerrequired"anthropic" | "openai"
modelrequiredstring
len 1..∞
api_keyrequiredstring
len 10..∞
system_promptrequiredstring
len 40..∞
max_tokensinteger
range 1..4096
temperaturenumber
range 0..2
daily_cost_cap_brlstring
pattern: ^\d+(\.\d{1,2})?$
handoff_phrasesstring[]
blocked_topicsobject[]
blocked_topic_fallback_responsestring
len 1..1000
max_context_messagesinteger
range 1..100
max_context_age_secondsinteger | null
memory_persistence"disabled" | "opt_in" | "opt_out"
enabledboolean

Response

FieldTypeNotes
idrequiredstring
objectrequired"ai_agent"
namerequiredstring
descriptionrequiredstring | null
providerrequired"anthropic" | "openai"
modelrequiredstring
environmentrequired"sandbox" | "production"
system_promptrequiredstring
current_prompt_versionrequiredinteger
range -∞..9007199254740991
max_tokensrequiredinteger
range -∞..9007199254740991
temperaturerequiredstring
daily_cost_cap_brlrequiredstring | null
handoff_phrasesrequiredstring[]
blocked_topicsrequiredobject[]
blocked_topic_fallback_responserequiredstring
max_context_messagesrequiredinteger
range -∞..9007199254740991
max_context_age_secondsrequiredinteger | null
memory_persistencerequired"disabled" | "opt_in" | "opt_out"
enabledrequiredboolean
api_key_suffixrequiredstring
archived_atrequiredstring<ISO-8601> | null
created_atrequiredstring<ISO-8601>
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
updated_atrequiredstring<ISO-8601>
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$

List

GET/v1/ai-agents

Query

FieldTypeNotes
limitrequiredinteger
range 1..100
starting_afterstring
include_archivedboolean

Response

FieldTypeNotes
objectrequired"list"
datarequiredobject[]
has_morerequiredboolean
next_cursorrequiredstring | null

Retrieve

GET/v1/ai-agents/{agent_id}

Response

FieldTypeNotes
idrequiredstring
objectrequired"ai_agent"
namerequiredstring
descriptionrequiredstring | null
providerrequired"anthropic" | "openai"
modelrequiredstring
environmentrequired"sandbox" | "production"
system_promptrequiredstring
current_prompt_versionrequiredinteger
range -∞..9007199254740991
max_tokensrequiredinteger
range -∞..9007199254740991
temperaturerequiredstring
daily_cost_cap_brlrequiredstring | null
handoff_phrasesrequiredstring[]
blocked_topicsrequiredobject[]
blocked_topic_fallback_responserequiredstring
max_context_messagesrequiredinteger
range -∞..9007199254740991
max_context_age_secondsrequiredinteger | null
memory_persistencerequired"disabled" | "opt_in" | "opt_out"
enabledrequiredboolean
api_key_suffixrequiredstring
archived_atrequiredstring<ISO-8601> | null
created_atrequiredstring<ISO-8601>
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
updated_atrequiredstring<ISO-8601>
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$

Update

PATCH/v1/ai-agents/{agent_id}

Request

FieldTypeNotes
namestring
len 1..120
descriptionstring | null
modelstring
len 1..∞
api_keystring
len 10..∞
system_promptstring
len 40..∞
max_tokensinteger
range 1..4096
temperaturenumber
range 0..2
daily_cost_cap_brlstring | null
handoff_phrasesstring[]
blocked_topicsobject[]
blocked_topic_fallback_responsestring
len 1..1000
max_context_messagesinteger
range 1..100
max_context_age_secondsinteger | null
memory_persistence"disabled" | "opt_in" | "opt_out"
enabledboolean
archivedboolean

Response

FieldTypeNotes
idrequiredstring
objectrequired"ai_agent"
namerequiredstring
descriptionrequiredstring | null
providerrequired"anthropic" | "openai"
modelrequiredstring
environmentrequired"sandbox" | "production"
system_promptrequiredstring
current_prompt_versionrequiredinteger
range -∞..9007199254740991
max_tokensrequiredinteger
range -∞..9007199254740991
temperaturerequiredstring
daily_cost_cap_brlrequiredstring | null
handoff_phrasesrequiredstring[]
blocked_topicsrequiredobject[]
blocked_topic_fallback_responserequiredstring
max_context_messagesrequiredinteger
range -∞..9007199254740991
max_context_age_secondsrequiredinteger | null
memory_persistencerequired"disabled" | "opt_in" | "opt_out"
enabledrequiredboolean
api_key_suffixrequiredstring
archived_atrequiredstring<ISO-8601> | null
created_atrequiredstring<ISO-8601>
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$
updated_atrequiredstring<ISO-8601>
pattern: ^(?:(?:\d\d[2468][048]|\d\d[13579][26]|\d\d0[48]|[02468][048]00|[13579][26]00)-02-29|\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\d|30)|(?:02)-(?:0[1-9]|1\d|2[0-8])))T(?:(?:[01]\d|2[0-3]):[0-5]\d(?::[0-5]\d(?:\.\d+)?)?(?:Z|([+-](?:[01]\d|2[0-3]):[0-5]\d)))$

Delete

DELETE/v1/ai-agents/{agent_id}

Response

FieldTypeNotes
idrequiredstring
deletedrequired"true"

Run a completion

POST/v1/ai-agents/{agent_id}/completions

Runs one completion against the agent persona. Policy enforcement runs before any provider call.

A completion with handoff: true returns empty content(no provider call, zero tokens and cost) — the agent deliberately declined to auto-reply so a human can take over. Treat it as a deliberate signal, not a missing reply. A blocked-topic match instead returns the agent's blocked_topic_fallback_response with handoff: false.
402 ai_agent_cost_cap_reached is returned synchronously when the agent's daily_cost_cap_brl has already been spent today — before any provider call — and emits ai_agent.cost_cap_reached.

Request

FieldTypeNotes
messagesrequiredobject[]
contact_phonestring
pattern: ^\+\d{8,15}$
trace_idstring

Response

FieldTypeNotes
objectrequired"ai_agent_completion"
ai_agent_idrequiredstring
contentrequiredstring
modelrequiredstring
tokens_inrequiredinteger
range 0..9007199254740991
tokens_outrequiredinteger
range 0..9007199254740991
cost_brlrequiredstring
handoffrequiredboolean
trace_idrequiredstring

List prompt versions

GET/v1/ai-agents/{agent_id}/prompt-versions

Query

FieldTypeNotes
limitrequiredinteger
range 1..100
starting_afterstring

Response

FieldTypeNotes
objectrequired"list"
datarequiredobject[]
has_morerequiredboolean
next_cursorrequiredstring | null

List response logs

GET/v1/ai-agents/{agent_id}/response-logs

Query

FieldTypeNotes
limitrequiredinteger
range 1..100
starting_afterstring

Response

FieldTypeNotes
objectrequired"list"
datarequiredobject[]
has_morerequiredboolean
next_cursorrequiredstring | null