agent_team puts several agents on one session, defined on the request that starts it. members[0] answers; the others are reachable through handoffs entries that name them. Every agent in the cast is an agent — a handoff between them is still agent → agent, never the transfer that reaches a person. Use it when the cast is generated per request and would never be reused. If the same three agents answer every call, they belong in the workspace with handoffs pointing at each other by agent_id, and the request names one agent_id.

Where it is accepted

Every member must be on a channel that endpoint runs; a member that resolves to the wrong one is a 400 naming the member and the endpoint to use instead. An inbound phone call has no request of ours, so it cannot carry a team. A number answers with the one agent assigned to it — which can still have handoffs naming stored agents by agent_id. See inbound calls.

The shape

Each member takes the same four fields a single-agent request takes, plus a name:
string
required
This member’s name for this call, winning over the stored agent’s own. Handoff edges reference it and the transcript records it. Names must be unique across the call.
uuid
An agent in this workspace. Mutually exclusive with agent. One of the two is required.
AgentConfig
A whole agent definition, run for this call and stored nowhere.
integer | "draft"
Which version of agent_id to run. Omit for the published one. Needs agent_id.
AgentOverride
Changes layered on the base. Absent keys keep the base value, an explicit null clears a field, objects deep-merge and lists replace wholesale.
agent_team is mutually exclusive with agent_id, agent, agent_version and agent_override at the top level of the request: one agent, or a team of them. Sending both is refused before anything runs.

How members reach each other

Every member is in the call’s roster under its name, the entry member included — which is what lets a specialist hand the call back to whoever answered. A handoff entry resolves in one of two ways:
  • With agent_id — a stored agent, at its latest published version. The team is not consulted, and the target does not have to be on it.
  • Without agent_id — the entry’s name is looked up in this call’s roster. A name nothing on the team defines is refused when the call is created.
A stored agent whose edges are name-only publishes with a warning, because its roster is unknowable until it runs. That is expected for an agent built to run in teams. The alternative, when the stored agent has ordinary agent_id edges and this one call needs different ones, is agent_override.handoffs — a list, so it replaces the stored edges wholesale for this call. Members nothing hands off to are a warning, not a refusal — a member reachable only after two hops is legitimate, and a typo is not:

What is checked, and when

Everything is resolved and validated before the call starts, by the same rules that guard publishing. A bad team is a 400 at create, naming the problem, rather than a call that connects and then fails. In particular:
  • Each member’s merged config must be a valid, publishable agent — including the cross-agent rules on handoffs, which run against the roster, so an edge whose target is on the wrong channel or the wrong pipeline is caught here.
  • A member naming a stored agent with no published version is refused: publish 'Renewals' before calling it.
  • Two members with the same name is a 422.
  • 1 to 10 members. Above ten, the shape being asked for is a workflow, not a team.
  • The resolved plan must be under 256 KB. A long inline definition multiplied by ten members is what this bounds; the error says how big the plan came out.
Version pinning has one rule: an override pins, a bare id follows published. A member with a stored base pins the version at request time, because its overrides were validated against exactly that base. A handoffs target named by agent_id carries no override, so it enters the target’s latest published version, as it does on a single-agent call. On a batch the plan is resolved once and every call it places runs that same cast.

userdata and vars across a team

One bag of each, per session, reaching every member — the entry agent, every other member, and a handoff target that was never on the team.
  • userdata is session state every agent shares. A tool on one member writes it and the next member reads it. It is merged onto the caller’s contact record like any other session’s.
  • vars are values for the variables the agents declare. They override each agent’s own declared defaults, so two members can declare the same name with different defaults and each falls back to its own. Nothing inside the session can write them.
required: true on a variable is checked once, at the door, against the merged cast: if any member requires a variable the request supplied no value and no default for, the session is refused before anything is compiled. Nothing is enforced after that, so a handoff target that needs a value nobody supplied reads it as empty rather than ending the call.

A worked example

A web call whose front desk routes to a renewals agent, with the front desk’s edges supplied for this call only.
server_url and participant_token are what a browser joins with — see web calls. The response also carries warnings, which is where the unreachable-member warning above turns up. The same agent_team object goes on POST /v1/calls/outbound, POST /v1/conversations and POST /v1/calls/batches unchanged.
Composing inline teams by habit ends with a workspace that has no agents in it. An agent defined inline has no editor, no version history, no diff and no reuse, and it disappears with the call. Prefer stored agents with agent_id, reach for agent_override when one call genuinely differs, and keep agent and inline teams for definitions that are generated per request.

Next

Handoffs

The edges members reach each other through.

Per-call configuration

agent_version, agent_override and inline agent on a single-agent call.

Patterns

When a cast genuinely differs per request, and when it does not.