> ## Documentation Index
> Fetch the complete documentation index at: https://docs.keebai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Agents overview

> Create agents, write the sections of their prompt, and give them webhook tools to call — the same configuration the Keebai portal edits.

An agent is what answers your customers. Its behaviour is not one prompt string: it is a **goal**, a set of **prompt sections** written by the business, the **channels** it answers on, and the **tools** it is allowed to call while it answers.

**This API edits that configuration.** Everything the portal's agent editor does, you can do here — which is what makes it possible to version your agents in git, provision them per client, or let an agent tune them.

## The four parts

<CardGroup cols={2}>
  <Card title="Goal" icon="bullseye">
    What the agent has to achieve. It decides which toolkits switch on, so it is the one part you cannot change casually.
  </Card>

  <Card title="Prompt sections" icon="file-lines">
    What the business contributes: who it is, what it does not do, when it hands over, its example conversations.
  </Card>

  <Card title="Channels" icon="comments">
    Where it answers. The mechanics of each medium come from the platform, not from your text.
  </Card>

  <Card title="Tools" icon="bolt">
    HTTPS webhooks the agent can call mid-conversation. They belong to the company; an agent uses one by holding its id.
  </Card>
</CardGroup>

## The catalogue is the source of truth

The valid values of `section`, `goal.type` and `channels` come from [`GET /v1/agents/prompt-types`](/dev/endpoints/prompt-types-list), not from a list published in this documentation.

That is deliberate. A section added to the platform appears in the catalogue immediately, and a list you copied into your code goes stale the day it happens. **Read the catalogue at build time or at run time; do not hardcode it.**

Each section row also carries a `tip` — the platform's own guidance on what belongs in that section. If you generate section text with a model, that `tip` is the instruction to give it.

## The read path

Two calls, and the second one already includes the text:

```bash theme={"system"}
TOKEN="kbai_pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

# 1. Which agents exist
curl -s https://api.keebai.com/v1/agents -H "Authorization: Bearer $TOKEN"

# 2. This agent whole: goal, sections with their text, channels, tools
curl -s https://api.keebai.com/v1/agents/6650a1b2c3d4e5f6a7b8c9d0 \
  -H "Authorization: Bearer $TOKEN"
```

## Writing sections

One section at a time with [`PUT /v1/agents/{id}/prompts/{section}`](/dev/endpoints/agents-prompt-set), which leaves the rest of the agent alone. Sending `prompts` to [the update endpoint](/dev/endpoints/agents-update) instead replaces **all** of them — useful when you own the whole prompt, dangerous when you do not.

```bash theme={"system"}
curl -X PUT https://api.keebai.com/v1/agents/6650a1b2c3d4e5f6a7b8c9d0/prompts/agent_limits \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"markdown": "Los precios los das del catálogo. Si no está, ofreces confirmarlo con el equipo."}'
```

Two things worth knowing before you automate it:

* **Send the whole section.** The text is replaced, not appended to.
* **Serialise your writes per agent.** A section is written by reading the agent, replacing that entry and saving it back, so two simultaneous writes to different sections of the same agent lose one.

## Sections have history

Every save that changes the text leaves a version behind. Saving identical text does not, so the history records changes rather than calls.

* [List the versions of a section](/dev/endpoints/agents-prompt-versions-list) — newest first; the first one is what the agent is reading.
* [Read one version](/dev/endpoints/agents-prompt-version-get) to diff it against the current text.
* [Restore one](/dev/endpoints/agents-prompt-version-restore) — which **writes a new version** copying the old one and records `restored_from`, so a rollback is itself reversible.

## The funnel

An agent moves tickets between the stages of a CRM pipeline — but **it never creates stages by itself**: its `stages` field is a whitelist of ones that already exist, and a stage that is not in the CRM enables nothing.

That is why [creating an agent](/dev/endpoints/agents-create) accepts `stages` as **names, in order**:

```json theme={"system"}
{ "name": "Camila", "stages": ["Nuevo", "Contactado", "Agendado", "Cerrado"] }
```

A pipeline is created in the CRM **named after the agent** with those stages, and the agent is allowed to move tickets only between them. Naming it after the agent is what lets a business with several agents look at the CRM and tell which funnel belongs to which.

Leave `stages` out and no pipeline is created and the agent does not move tickets — which is the right answer for one that only informs.

## Testing an agent

[`POST /v1/agents/{id}/query`](/dev/endpoints/agents-query) writes to the agent as if you were a customer and returns what it answers.

It **always runs in test mode**, and that is not configurable. The tools that write — booking, charging, opening a ticket — are simulated, and the response tells you which ones were called and which were simulated. A public endpoint that ran them for real would give any PAT the ability to create appointments and charges on behalf of the business, without the token's scopes having any say: what a tool does is governed by the agent, not by the token.

Real customer conversations go through the channels, not through this.

## Tools

A tool is an HTTPS webhook with a name, a description and typed parameters. The description is what the model reads to decide when to call it, so it is configuration that matters, not a label.

Tools live at the **company** level: [list them](/dev/endpoints/tools-list) once, and give an agent the ids it should be allowed to use. The URL rules and the masking of secret values are in [webhook security](/dev/agents/webhook-security).

## Migrating from the block API

The previous version of this surface modelled a prompt as an ordered list of **blocks** living in a project catalogue, each with its own versions. That model is gone.

| Before                                                                           | Now                                                                                                                                                                                                  |
| -------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GET/PUT/POST /v1/agents/{id}/blocks`, `DELETE /v1/agents/{id}/blocks/{blockId}` | [`GET /v1/agents/{id}/prompts`](/dev/endpoints/agents-prompts-list), [`PUT`](/dev/endpoints/agents-prompt-set) / [`DELETE`](/dev/endpoints/agents-prompt-delete) `/v1/agents/{id}/prompts/{section}` |
| `/v1/blocks/*` — catalogue, content, versions                                    | No equivalent. The text lives inside the agent, and [versions hang off the section](/dev/endpoints/agents-prompt-versions-list).                                                                     |
| `/v1/functions/*`                                                                | [`/v1/tools/*`](/dev/endpoints/tools-list)                                                                                                                                                           |
| `avatar_url`, `avatar_emoji` on the agent                                        | No equivalent. They were accepted and discarded.                                                                                                                                                     |

Three differences that change how you integrate, not just what you call:

* **A section is not shared.** Blocks lived in a catalogue and several agents could reference the same one; a section belongs to its agent. Reuse across agents is now your templating, not a shared object.
* **There is no attach and detach.** Writing a section creates it; deleting it removes it.
* **Content and metadata are no longer separate calls.** Reading the agent gives you the text.

There is no `assistants` surface any more. The `/v1/assistants` alias is gone, responses carry `agent` and nothing else, and the not-found code is `AGENT_NOT_FOUND`. `agents-list`, `agents-get`, `agents-create`, `agents-update` and `agents-delete` keep their URLs even though their shape changed.
