AI Agents
An agent that answerswhere the customer already writes.
Prompt, model, tools and knowledge base are one object. Create it over the API, connect the senders it should answer on, and run it against a message before anything is delivered.
- openai · anthropic · google · mistral · zavu
- one agent, several senders
- dry run before you ship
The loop
Watch a reply get made.
One inbound message, retrieval, a tool the model chose, an answer. Switch between a dry run and the live path and the record at the bottom changes with it.
Ask the agent
POST /v1/agents/{agentId}/test. Nothing is delivered, nothing is charged, no execution is stored.
Pick a question and run the loop.
Retrieval returns at most 5 chunks above a similarity floor. A reply grounded in nothing looks exactly like a correct one — which is why the count is on the record.
Build it
Four calls and it is answering.
Agents are configured over REST, from the CLI, or declared in code with @zavudev/functions. @zavudev/sdk does not generate an agents resource yet, so nothing here pretends it does.
# Create a standalone agent — no sender needed yet.
AGENT=$(curl -s -X POST https://api.zavu.dev/v1/agents \
-H "Authorization: Bearer $ZAVU_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Support",
"provider": "zavu",
"model": "openai/gpt-4o-mini",
"systemPrompt": "You answer order questions. Be brief.",
"triggerOnChannels": ["whatsapp", "sms", "email"]
}' | jq -r .agent.id)
# Point it at the number it should answer on, then turn it on.
curl -X POST https://api.zavu.dev/v1/agents/$AGENT/senders \
-H "Authorization: Bearer $ZAVU_API_KEY" \
-d "{\"senderId\":\"$SENDER_ID\"}"
curl -X PATCH https://api.zavu.dev/v1/agents/$AGENT \
-H "Authorization: Bearer $ZAVU_API_KEY" \
-d '{"enabled": true}'Channels
One agent. The channels you let it have.
triggerOnChannels is checked before anything else runs. Build the list on the left and see whether the inbound message reaches the model at all.
Message arrives on
triggerOnChannels
Empty means the agent answers nothing. The wildcard covers every channel the sender can actually receive on.
agent config
{
"triggerOnChannels": ["whatsapp", "sms", "email"]
}processed — the agent answers
Do you ship to Chile?
We do. Chile is around six working days, duties paid at checkout.
Same prompt, same knowledge base, same tools. The channel only decides where the answer leaves from.
Anatomy
What an agent is made of.
Prompt and model
openai, anthropic, google or mistral with your own key — or zavu, for models Zavu hosts, where no key is needed.
- System prompt ≤ 10,000 chars
- Context window 1–50 messages
- Temperature 0–2
Knowledge bases
Documents are chunked and embedded on write. The retrieval that runs before every reply pulls the closest chunks into the prompt.
- ≤ 100,000 chars per document
- ≤ 5 chunks per reply
- knowledgeChunksUsed on every run
Tools
An HTTPS endpoint you own, described with a JSON Schema. Zavu signs every call so your handler can refuse anything it did not send.
- X-Zavu-Signature: HMAC-SHA256
- Fire one by hand with /test
- Recent runs via /test-runs
Flows
A scripted sequence that runs ahead of the model when a keyword matches, or on every message. Steps collect data, branch, call a tool, or hand back to the LLM.
- keyword and always triggers
- message · collect · condition
- tool · llm steps
Senders
One agent answers on as many senders as you connect. A sender answers with at most one agent — connecting one that is taken returns 400 naming the agent that holds it.
- POST /v1/agents/{id}/senders
- senderIds on the agent
- Standalone agents allowed
Executions
Every reply is stored: tokens, latency, cost, the chunks it retrieved and the tools it called. Fetch one to read the error message behind a failure.
- knowledgeChunksUsed · toolCalls
- success · error · filtered
- rate_limited · balance_insufficient
Questions
The ones that decide it.
Can I test an agent without messaging anyone?
Yes. POST /v1/agents/{agentId}/test — or npx zavudev agents test — runs the real prompt, model and knowledge base and returns what the agent would say, with tokens, latency and knowledgeChunksUsed. Nothing is delivered, nothing is charged, no execution is stored. Pass executeTools when you want the tool handlers to actually run.
Which model providers can I use?
openai, anthropic, google and mistral with your own API key, or zavu for models Zavu hosts, which needs no key of yours. The provider is a field on the agent, so switching is a PATCH.
How does a tool call reach my code?
As an HTTPS POST to the URL you registered, carrying the tool name, the arguments the model chose, conversation context and a timestamp. It arrives with X-Zavu-Tool, X-Zavu-Timestamp and X-Zavu-Signature — the HMAC-SHA256 of the body, keyed with the tool's secret. Verify the signature before you trust the call.
Can one agent serve several numbers?
Yes. Connect senders with POST /v1/agents/{agentId}/senders and they all resolve to the same prompt, tools and knowledge bases. The reverse is capped: a sender answers with at most one agent.
Is there an SDK method for agents?
Not yet. @zavudev/sdk generates messages, senders, contacts, templates, broadcasts, phone numbers and more, but no agents resource. Configure agents over REST, with the npx zavudev CLI, or declare them in code with @zavudev/functions and deploy.
What does it cost to run?
Model tokens and the channel the reply leaves on. There is no per-agent fee and no cap on how many you create. Every execution stores its own cost, so the bill is itemised by reply.
Reading
Guides for building agents
The loop, the channels, and the decisions that come before the code.
Ship one this afternoon.
Create the agent, connect a sender, dry-run it until the answer is right. Then let it answer.