Response Components API
Read and set how often an agent answers with an interactive response component, and which components it may use, over the agents REST API. The frequency is the same dial as the dashboard's Component frequency select.
On this page
An agent can attach a response component to its reply in the
Web SDK — a clickable confirm, a select list, a formatted
card, or a list of results. How often it reaches for one is a per-agent setting, responseComponents.frequency, carried
on the public agents API. The same setting is the Component frequency select under
Choice buttons in the dashboard's agent settings; either path
writes the one value, and this page covers the API. Which components the agent may use at all is a
second per-agent setting on the same field, the per-component switches in
responseComponents.components — see Choosing components.
Authenticate with a bearer API key, created under Settings → API keys (where available). If your organization doesn't show that item, open Settings → Members, which opens your organization's account page, and manage keys in its API Keys section; see API keys. Full request and response schemas live in the OpenAPI reference.
Endpoints#
| Endpoint | Purpose |
|---|---|
GET /v1/agents?ids=… | Read the level for several agents. ids is required — a comma-separated list of up to 100 agent ids; omitting it is a 400 |
GET /v1/agents/{id} | Read the level for one agent |
PATCH /v1/agents/{id} | Set the level, the per-component switches, or both |
PATCH requires an API key with the manageAgents capability. Reads do not. That capability is the
public-surface equivalent of the dashboard's feature:write permission, which is a per-user
dashboard permission with no representation on an API key — so do not look for feature:write on a
key, and do not expect a key to inherit the dashboard permissions of whoever created it. Keys are
issued from the dashboard by an organization admin or owner.
The dashboard is the second write path. There the dial is gated by feature:write itself, and it
applies the same rule as the 422 below: a non-off level is refused on an agent type that cannot
emit components.
POST /v1/agents does not accept responseComponents; the field is ignored rather than
rejected, so a create carrying it still returns 201 with the dial at off. Create the agent, then
set the dial with a follow-up PATCH.
Reading the level#
responseComponents is a required field on every agent payload — GET /v1/agents,
GET /v1/agents/{id}, and the create and update responses. Abridged to the relevant fields:
{
"id": "0f2b7d1e-9c34-4a5b-8f61-2ad0c5e7b913",
"name": "Support agent",
"longTermMemory": { "enabled": true },
"responseComponents": {
"frequency": "medium",
"components": { "choiceButtons": true, "card": true, "list": false, "table": false, "chart": false }
}
}An agent that has never had the dial set reads back as "off". components is always the complete
map: every switch, with its default filled in where nothing was set. New switches may be added to
it later, so treat a key you do not recognize as one more switch rather than an error.
Setting the level#
curl -X PATCH https://api.runbear.io/v1/agents/0f2b7d1e-9c34-4a5b-8f61-2ad0c5e7b913 \
-H "Authorization: Bearer $RUNBEAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"responseComponents":{"frequency":"medium"}}'The response is the full agent, with responseComponents.frequency reflecting the write.
frequency is optional: a request can carry only components (see
Choosing components), and an omitted frequency keeps its stored value.
The levels#
| Level | What it does |
|---|---|
off | The agent is not offered the components at all on this channel. This is the default, and the value an unset or unrecognized stored level reads back as. |
low | Offer buttons sparingly: only when the next reply is unambiguously one of a few concrete options, and at most once per turn. |
medium | The balanced setting. Offer buttons whenever the next reply is plausibly one of a few concrete options; answer in prose when the question is genuinely open-ended. |
high | Offer buttons at every reasonable opportunity — whenever the turn would end in a question, a list of suggestions, or any choice the visitor could type back. |
Choosing components#
The per-component switches choose which components the agent may use on the Web SDK. Each switch covers one or more components:
| Switch | Components | Default |
|---|---|---|
choiceButtons | confirm, select | On |
card | card | On |
list | list | Off |
table | table | Off |
chart | chart | Off |
Turn a switch on or off with a PATCH carrying only the switches you change:
curl -X PATCH https://api.runbear.io/v1/agents/0f2b7d1e-9c34-4a5b-8f61-2ad0c5e7b913 \
-H "Authorization: Bearer $RUNBEAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"responseComponents":{"components":{"list":true}}}'- Only the switches you send change. The rest keep their stored value, and a switch you never set keeps following its default.
- The request is strict. An unknown switch, or a value that is not
trueorfalse, is rejected with400bad_requestbefore anything is stored. - Turning on a component the agent's type cannot emit is refused with
422unsupported_for_agent_type, and the message names the refused switches. Aclaude-agent-sdkagent supports only thechoiceButtonsswitch, and ageminiagent supports none. Sendingtruefor a switch that already reads back astrueis accepted, so a map you read can be sent back unchanged. - Turning a switch off is always accepted, on every agent type.
The switches choose among components only while the dial is on. frequency set to "off" still
withholds every component on the Web SDK, whatever the switches say. With the choiceButtons switch
off, the low, medium and high levels read the same: their guidance is about the choice
buttons.
The choiceButtons switch is not the agent's Choice Buttons setting
(disableInteractivePrompts). The setting is the agent-wide opt-out: turning it off withdraws every
component on every surface, whatever the switches say. The choiceButtons switch only decides
whether confirm and select are offered on the Web SDK, and it never affects Slack.
A switch for a component that is not yet available (table, chart) stores and reads back like
any other and produces nothing until it is. list, table and chart render on
@runbear-io/react 0.5.0 or newer.
What else has to be true#
The dial is necessary but not sufficient. A non-off level produces components in the Web SDK only
when all of these also hold:
- Response components are enabled for your organization. They are in limited availability, and
Runbear turns them on per organization (see the callout at the top of this page). Until then a
non-
offlevel stores and reads back correctly and produces nothing. - The agent's Choice Buttons setting is on. Turning it off withdraws interactive prompts on every surface, and it is checked before this dial. An agent opted out there never gains web components, whatever the level says.
- The run has someone waiting on it. Scheduled and other automated runs never offer components, whatever the level says.
- Your widget is on an SDK release that carries the renderers. That is
@runbear-io/react0.3.0 or newer forconfirmandselect, 0.4.0 or newer forcard, and 0.5.0 or newer forlistand for a card's image and links. On an earlier release the component arrives on the wire and the widget shows its prose fallback — see Web SDK response components.
Which components the agent can reach for also depends on its type. anthropic and
openai-responses agents can emit every built-in component, and so can mastra agents — their dial is set from
the dashboard, because mastra is not exposed on /v1/agents. A claude-agent-sdk agent emits
confirm and select only, and never a card or a list, at any level. gemini emits none, which is why the dial refuses
to leave off there at all.
Because the per-organization switch and the Choice Buttons setting are separate, a GET
returning "frequency": "high" is a statement about this agent's configuration, not a promise that
a visitor will see a button.
Errors#
| Status | Body | Cause |
|---|---|---|
400 | { "error": "bad_request", … } | frequency is not one of off, low, medium, high. |
400 | { "error": "bad_request", … } | components names an unknown switch, or a switch's value is not true or false. |
422 | { "error": "unsupported_for_agent_type", "message": … } | A non-off level was written to an agent whose type cannot emit response components, or components turned on a switch the agent's type cannot emit. The message names the refused switches. |
The 422 is terminal for that agent: the dial is only meaningful on a type that supports the
components, and no retry changes that. On the public agents API this is refused for gemini, which
registers no tools at all. The agent types that predate this API — perplexity, upstage and
openai-assistant — also cannot emit components, but they are not exposed on /v1/agents and so
cannot be reached to be refused.
Writing "off" is accepted on every type, so an agent can always be returned to the default
even if it could not be given a level in the first place.
Related#
- Web SDK response components — the rendering contract: the wire event, the props shapes, the server limits, and what a click does
- Choice buttons — the dashboard section that holds this dial as Component frequency, and the switch that is checked before it
- API keys — creating the key that carries
manageAgents - OpenAPI reference — exact schemas for the agents endpoints