Team
Compose multiple AI agents into a directed graph for multi-agent conversations. Teams enable structured handoffs between specialized AI personas — for example, a receptionist that qualifies intent, then transfers to a billing specialist or a technical support agent — all within a single call.
API Reference: Team endpoints
Overview
Note
AI Context
Complexity: Medium
Cost: Chargeable (credit deduction per AI session — each member consumes LLM, TTS, and STT credits while active)
Async: Yes. Team conversations run asynchronously during calls. Monitor via
GET /calls/{id}or WebSocket events.
A Team models a multi-agent conversation as a directed graph. Each node in the graph is a Member backed by a reusable AI configuration. Directed edges between members are Transitions — LLM tool-functions that, when invoked by the currently active AI, hand the conversation to the next member.
Note
AI Implementation Hint
A Team is a configuration resource, not a runtime entity. You create a Team via POST /teams, then reference it in a flow action (e.g., ai_talk with team_id) to activate it during a call. The Team itself does not start conversations — it defines the graph that the flow engine traverses.
How it works
Architecture
+-----------------------------------------------------------------------+
| Team Conversation Architecture |
+-----------------------------------------------------------------------+
1. TEAM DEFINITION (design-time)
+---------------------+
| Team |
| start_member_id: A |
+----------+----------+
|
+----------v----------+ +---------------------+
| Member A | | Member B |
| "Receptionist" |------>| "Billing Agent" |
| ai_id: <uuid-A> | xfer | ai_id: <uuid-B> |
+-----------+----------+ _to_ +---------------------+
| billing
|
| xfer_to_support
v
+---------------------+
| Member C |
| "Support Agent" |
| ai_id: <uuid-C> |
+---------------------+
2. RUNTIME (during a call)
Caller ──> Member A (Receptionist)
│
│ LLM invokes "xfer_to_billing"
v
Member B (Billing Agent)
│
│ LLM invokes "xfer_to_support" (if defined)
v
Member C (Support Agent)
Graph Model
A Team is a directed graph where:
Nodes are Members. Each member wraps an existing AI configuration (
ai_id), inheriting its LLM, TTS, STT, prompt, and tools.Edges are Transitions. Each transition is an LLM tool-function (
function_name) with a human-readabledescriptionthe LLM uses to decide when to invoke it. When triggered, the conversation switches tonext_member_id.Entry point is the
start_member_idon the Team. The conversation begins with this member when the flow action activates the team.
+-----------------------------------------------------------------------+
| Graph Model |
+-----------------------------------------------------------------------+
Members (nodes) Transitions (edges)
+-----------+ +------------------------------+
| id |---<defines>---→| function_name |
| name | | description |
| ai_id | | next_member_id → Member.id |
+-----------+ +------------------------------+
Conversation Flow
When a flow action references a Team:
The system starts the conversation with the member identified by
start_member_id.The active member’s AI configuration (prompt, LLM, TTS, STT, tools) drives the conversation.
Transitions are injected into the LLM as additional tool-functions. The LLM’s
descriptionfield tells the model when to trigger each transition.When the LLM invokes a transition’s
function_name, the system seamlessly switches tonext_member_id. The new member’s AI configuration takes over.This repeats until the call ends, the flow stops, or no further transitions are available.
Note
AI Implementation Hint
Transition descriptions act as instructions to the LLM. Write them as clear conditions: "Transfer to billing when the caller asks about invoices, payments, or account charges." Vague descriptions ("Transfer to billing" without context) may cause the LLM to trigger transitions unexpectedly.
Runtime Behavior
When a team is activated during a call, the system handles member switching automatically:
Service switching:
Each member carries its own LLM, TTS, and STT configuration (inherited from its ai_id). When a transition fires, the system switches all three services to the new member’s configuration. The caller hears the new member’s TTS voice immediately after the transition.
Tool availability:
Each member’s AI tools (defined via tool_names on the AI configuration) are available only while that member is active. When a transition fires, the new member’s tools replace the previous member’s tools. Transition functions themselves are always available alongside the member’s regular tools.
STT language:
The speech-to-text language is shared across all members in a team and is determined by the call’s STT configuration — not per-member. All members use the same STT language for the duration of the call.
Graceful fallback:
If a member does not have a TTS or STT service configured (e.g., tts_type is empty on its AI), the system keeps the previous member’s TTS or STT service active. This prevents silence or deafness during the conversation.
Note
AI Implementation Hint
For the best caller experience, configure consistent STT types across all members in a team. While the system gracefully falls back to the previous member’s service, mixing STT providers mid-conversation may cause subtle differences in transcription behavior.
Use Cases
Customer service routing — A receptionist AI qualifies intent and routes to specialized agents (billing, support, sales).
Multi-step onboarding — A greeting agent collects basic info, then hands off to a verification agent, then to an account setup agent.
Escalation chains — A first-line support AI attempts resolution, then escalates to a senior agent if needed.
Survey + follow-up — A survey agent collects responses, then transitions to a follow-up agent for scheduling or issue resolution.
Team
Team
{
"id": "<string>",
"customer_id": "<string>",
"name": "<string>",
"detail": "<string>",
"start_member_id": "<string>",
"members": [
{
"id": "<string>",
"name": "<string>",
"ai_id": "<string>",
"transitions": [
{
"function_name": "<string>",
"description": "<string>",
"next_member_id": "<string>"
}
]
}
],
"parameter": "<object>",
"tm_create": "<string>",
"tm_update": "<string>",
"tm_delete": "<string>"
}
id(UUID): The team’s unique identifier. Returned when creating a team viaPOST /teamsor when listing teams viaGET /teams.customer_id(UUID): The customer that owns this team. Obtained from theidfield ofGET /customer.name(String, Required): A human-readable name for the team (e.g.,"Customer Service Team").detail(String, Optional): A description of the team’s purpose or additional notes.start_member_id(UUID, Required): The member where the conversation begins. Must match one of theidvalues in themembersarray.members(Array of Member, Required): The list of members (nodes) in the team graph. At least one member is required. See Member.parameter(Object, Optional): Custom key-value parameter data for the team. Supports flow variable substitution at runtime.tm_create(String, ISO 8601): Timestamp when the team was created.tm_update(String, ISO 8601): Timestamp when the team was last updated.tm_delete(String, ISO 8601): Timestamp when the team was deleted, if applicable.
Note
AI Implementation Hint
A tm_delete value of 9999-01-01 00:00:00.000000 indicates the team has not been deleted and is still active. This sentinel value is used across all VoIPBIN resources to represent “not yet occurred.”
Example
{
"id": "c3d4e5f6-a7b8-9012-cdef-345678901234",
"customer_id": "5e4a0680-804e-11ec-8477-2fea5968d85b",
"name": "Customer Service Team",
"detail": "Routes callers to the right specialist based on intent",
"start_member_id": "d4e5f6a7-b8c9-0123-defa-456789012345",
"members": [
{
"id": "d4e5f6a7-b8c9-0123-defa-456789012345",
"name": "Receptionist",
"ai_id": "a092c5d9-632c-48d7-b70b-499f2ca084b1",
"transitions": [
{
"function_name": "transfer_to_billing",
"description": "Transfer to the billing specialist when the caller asks about invoices, payments, charges, or account balance.",
"next_member_id": "e5f6a7b8-c9d0-1234-efab-567890123456"
},
{
"function_name": "transfer_to_support",
"description": "Transfer to technical support when the caller reports a technical issue, outage, or needs troubleshooting help.",
"next_member_id": "f6a7b8c9-d0e1-2345-fabc-678901234567"
}
]
},
{
"id": "e5f6a7b8-c9d0-1234-efab-567890123456",
"name": "Billing Specialist",
"ai_id": "b193d6ea-743d-59e8-c81c-5aaf3a195bc2",
"transitions": []
},
{
"id": "f6a7b8c9-d0e1-2345-fabc-678901234567",
"name": "Technical Support",
"ai_id": "c294e7fb-854e-6af9-d92d-6bb04b206cd3",
"transitions": [
{
"function_name": "escalate_to_receptionist",
"description": "Transfer back to the receptionist if the caller wants to discuss a different topic.",
"next_member_id": "d4e5f6a7-b8c9-0123-defa-456789012345"
}
]
}
],
"parameter": {
"language": "en",
"department": "customer-service"
},
"tm_create": "2026-02-27 10:00:00.000000",
"tm_update": "9999-01-01 00:00:00.000000",
"tm_delete": "9999-01-01 00:00:00.000000"
}
Member
A member is a node in the team graph, backed by an existing AI configuration.
{
"id": "<string>",
"name": "<string>",
"ai_id": "<string>",
"transitions": [
{
"function_name": "<string>",
"description": "<string>",
"next_member_id": "<string>"
}
]
}
id(UUID, Required): A client-provided UUID that uniquely identifies this member within the team. You generate this value (e.g., viauuidgen) when creating the team. Must be unique across themembersarray. Referenced bystart_member_idon the Team andnext_member_idon Transitions.name(String, Required): A human-readable label for this member (e.g.,"Receptionist","Billing Agent"). Used for logging and identification; not exposed to the caller.ai_id(UUID, Required): The AI configuration that drives this member’s behavior. Obtained from theidfield ofPOST /aisorGET /ais. The referenced AI defines the LLM, TTS, STT, prompt, and tools for this member.transitions(Array of Transition, Optional): Outgoing edges from this member. Each transition defines an LLM tool-function that hands the conversation to another member. See Transition. An empty array means this is a terminal node — the conversation stays with this member until the call ends.
Note
AI Implementation Hint
The ai_id must reference a valid, existing AI configuration. If the referenced AI is deleted, the team will fail to start a conversation for this member. Verify the AI exists via GET /ais/{ai_id} before assigning it to a member.
Transition
A transition is a directed edge between two members, implemented as an LLM tool-function.
{
"function_name": "<string>",
"description": "<string>",
"next_member_id": "<string>"
}
function_name(String, Required): The tool-function name the LLM will invoke to trigger this transition. Must be a valid identifier (letters, digits, underscores). Example:"transfer_to_billing".description(String, Required): A natural-language description of when to trigger this transition. The LLM uses this to decide whether to invoke the function. Write clear, specific conditions. Example:"Transfer to the billing specialist when the caller asks about invoices, payments, or account charges.".next_member_id(UUID, Required): The member to hand the conversation to when this transition fires. Must match anidin the team’smembersarray.
Note
AI Implementation Hint
function_name values must be unique within a member’s transitions array. Duplicate names will cause unpredictable LLM behavior. Use descriptive, action-oriented names like transfer_to_billing rather than generic names like next.
Tutorial
Before creating a team, you need:
A valid authentication token (String). Obtain via
POST /auth/loginor use an accesskey fromGET /accesskeys.At least two AI configurations (UUIDs). Create them via
POST /aisor obtain fromGET /ais. Each AI defines a distinct persona with its own LLM, prompt, TTS, and STT settings.
Note
AI Implementation Hint
Each member in a team references an independent AI configuration. Design each AI’s init_prompt for a specific role (e.g., receptionist, billing specialist). The team’s graph structure handles routing — individual AIs do not need to know about each other.
Step 1: Create AI Configurations
First, create the AI configurations that will back each team member. In this example, we create a receptionist and a billing specialist.
Create Receptionist AI:
$ curl --location --request POST 'https://api.voipbin.net/v1.0/ais?token=<YOUR_AUTH_TOKEN>' \
--header 'Content-Type: application/json' \
--data-raw '{
"name": "Receptionist AI",
"detail": "Qualifies caller intent and routes to the right specialist",
"engine_model": "openai.gpt-4o",
"engine_key": "sk-...",
"init_prompt": "You are a friendly receptionist. Greet the caller, ask how you can help, and determine if they need billing assistance or technical support.",
"tts_type": "elevenlabs",
"stt_type": "deepgram",
"tool_names": ["all"]
}'
Response:
{
"id": "a092c5d9-632c-48d7-b70b-499f2ca084b1", // Save this as receptionist_ai_id
"customer_id": "5e4a0680-804e-11ec-8477-2fea5968d85b",
"name": "Receptionist AI",
...
}
Create Billing AI:
$ curl --location --request POST 'https://api.voipbin.net/v1.0/ais?token=<YOUR_AUTH_TOKEN>' \
--header 'Content-Type: application/json' \
--data-raw '{
"name": "Billing Specialist AI",
"detail": "Handles billing inquiries, payment issues, and account charges",
"engine_model": "openai.gpt-4o",
"engine_key": "sk-...",
"init_prompt": "You are a billing specialist. Help callers with invoices, payments, charges, and account balance questions. Be precise with numbers and dates.",
"tts_type": "elevenlabs",
"stt_type": "deepgram",
"tool_names": ["all"]
}'
Response:
{
"id": "b193d6ea-743d-59e8-c81c-5aaf3a195bc2", // Save this as billing_ai_id
"customer_id": "5e4a0680-804e-11ec-8477-2fea5968d85b",
"name": "Billing Specialist AI",
...
}
Step 2: Create the Team
Create a team with two members (receptionist and billing specialist) and a transition from the receptionist to the billing specialist.
$ curl --location --request POST 'https://api.voipbin.net/v1.0/teams?token=<YOUR_AUTH_TOKEN>' \
--header 'Content-Type: application/json' \
--data-raw '{
"name": "Customer Service Team",
"detail": "Routes callers to the right specialist based on intent",
"start_member_id": "d4e5f6a7-b8c9-0123-defa-456789012345",
"members": [
{
"id": "d4e5f6a7-b8c9-0123-defa-456789012345",
"name": "Receptionist",
"ai_id": "a092c5d9-632c-48d7-b70b-499f2ca084b1",
"transitions": [
{
"function_name": "transfer_to_billing",
"description": "Transfer to the billing specialist when the caller asks about invoices, payments, charges, or account balance.",
"next_member_id": "e5f6a7b8-c9d0-1234-efab-567890123456"
}
]
},
{
"id": "e5f6a7b8-c9d0-1234-efab-567890123456",
"name": "Billing Specialist",
"ai_id": "b193d6ea-743d-59e8-c81c-5aaf3a195bc2",
"transitions": [
{
"function_name": "transfer_to_receptionist",
"description": "Transfer back to the receptionist if the caller wants help with something other than billing.",
"next_member_id": "d4e5f6a7-b8c9-0123-defa-456789012345"
}
]
}
],
"parameter": {
"language": "en",
"department": "customer-service"
}
}'
Response:
{
"id": "c3d4e5f6-a7b8-9012-cdef-345678901234", // Save this as team_id
"customer_id": "5e4a0680-804e-11ec-8477-2fea5968d85b",
"name": "Customer Service Team",
"detail": "Routes callers to the right specialist based on intent",
"start_member_id": "d4e5f6a7-b8c9-0123-defa-456789012345",
"members": [
{
"id": "d4e5f6a7-b8c9-0123-defa-456789012345",
"name": "Receptionist",
"ai_id": "a092c5d9-632c-48d7-b70b-499f2ca084b1",
"transitions": [
{
"function_name": "transfer_to_billing",
"description": "Transfer to the billing specialist when the caller asks about invoices, payments, charges, or account balance.",
"next_member_id": "e5f6a7b8-c9d0-1234-efab-567890123456"
}
]
},
{
"id": "e5f6a7b8-c9d0-1234-efab-567890123456",
"name": "Billing Specialist",
"ai_id": "b193d6ea-743d-59e8-c81c-5aaf3a195bc2",
"transitions": [
{
"function_name": "transfer_to_receptionist",
"description": "Transfer back to the receptionist if the caller wants help with something other than billing.",
"next_member_id": "d4e5f6a7-b8c9-0123-defa-456789012345"
}
]
}
],
"parameter": {
"language": "en",
"department": "customer-service"
},
"tm_create": "2026-02-27 10:00:00.000000",
"tm_update": "9999-01-01 00:00:00.000000",
"tm_delete": "9999-01-01 00:00:00.000000"
}
Step 3: Get Team Details
Retrieve the team to verify its configuration.
$ curl --location --request GET 'https://api.voipbin.net/v1.0/teams/c3d4e5f6-a7b8-9012-cdef-345678901234?token=<YOUR_AUTH_TOKEN>'
Response:
{
"id": "c3d4e5f6-a7b8-9012-cdef-345678901234",
"customer_id": "5e4a0680-804e-11ec-8477-2fea5968d85b",
"name": "Customer Service Team",
"detail": "Routes callers to the right specialist based on intent",
"start_member_id": "d4e5f6a7-b8c9-0123-defa-456789012345",
"members": [
{
"id": "d4e5f6a7-b8c9-0123-defa-456789012345",
"name": "Receptionist",
"ai_id": "a092c5d9-632c-48d7-b70b-499f2ca084b1",
"transitions": [...]
},
{
"id": "e5f6a7b8-c9d0-1234-efab-567890123456",
"name": "Billing Specialist",
"ai_id": "b193d6ea-743d-59e8-c81c-5aaf3a195bc2",
"transitions": [...]
}
],
"parameter": {
"language": "en",
"department": "customer-service"
},
"tm_create": "2026-02-27 10:00:00.000000",
"tm_update": "9999-01-01 00:00:00.000000",
"tm_delete": "9999-01-01 00:00:00.000000"
}
Step 4: Update a Team
Add a third member (Technical Support) to the existing team.
$ curl --location --request PUT 'https://api.voipbin.net/v1.0/teams/c3d4e5f6-a7b8-9012-cdef-345678901234?token=<YOUR_AUTH_TOKEN>' \
--header 'Content-Type: application/json' \
--data-raw '{
"name": "Customer Service Team",
"detail": "Routes callers to billing or technical support",
"start_member_id": "d4e5f6a7-b8c9-0123-defa-456789012345",
"members": [
{
"id": "d4e5f6a7-b8c9-0123-defa-456789012345",
"name": "Receptionist",
"ai_id": "a092c5d9-632c-48d7-b70b-499f2ca084b1",
"transitions": [
{
"function_name": "transfer_to_billing",
"description": "Transfer to the billing specialist when the caller asks about invoices, payments, charges, or account balance.",
"next_member_id": "e5f6a7b8-c9d0-1234-efab-567890123456"
},
{
"function_name": "transfer_to_support",
"description": "Transfer to technical support when the caller reports a technical issue, outage, or needs troubleshooting help.",
"next_member_id": "f6a7b8c9-d0e1-2345-fabc-678901234567"
}
]
},
{
"id": "e5f6a7b8-c9d0-1234-efab-567890123456",
"name": "Billing Specialist",
"ai_id": "b193d6ea-743d-59e8-c81c-5aaf3a195bc2",
"transitions": [
{
"function_name": "transfer_to_receptionist",
"description": "Transfer back to the receptionist if the caller wants help with something other than billing.",
"next_member_id": "d4e5f6a7-b8c9-0123-defa-456789012345"
}
]
},
{
"id": "f6a7b8c9-d0e1-2345-fabc-678901234567",
"name": "Technical Support",
"ai_id": "c294e7fb-854e-6af9-d92d-6bb04b206cd3",
"transitions": [
{
"function_name": "escalate_to_receptionist",
"description": "Transfer back to the receptionist if the caller wants to discuss a different topic.",
"next_member_id": "d4e5f6a7-b8c9-0123-defa-456789012345"
}
]
}
],
"parameter": {
"language": "en",
"department": "customer-service"
}
}'
Response:
{
"id": "c3d4e5f6-a7b8-9012-cdef-345678901234",
"customer_id": "5e4a0680-804e-11ec-8477-2fea5968d85b",
"name": "Customer Service Team",
"detail": "Routes callers to billing or technical support",
"start_member_id": "d4e5f6a7-b8c9-0123-defa-456789012345",
"members": [
...
],
"parameter": {
"language": "en",
"department": "customer-service"
},
"tm_create": "2026-02-27 10:00:00.000000",
"tm_update": "2026-02-27 10:05:00.000000",
"tm_delete": "9999-01-01 00:00:00.000000"
}
Step 5: List Teams
List all teams owned by your account.
$ curl --location --request GET 'https://api.voipbin.net/v1.0/teams?token=<YOUR_AUTH_TOKEN>'
Response:
{
"result": [
{
"id": "c3d4e5f6-a7b8-9012-cdef-345678901234",
"customer_id": "5e4a0680-804e-11ec-8477-2fea5968d85b",
"name": "Customer Service Team",
"detail": "Routes callers to billing or technical support",
"start_member_id": "d4e5f6a7-b8c9-0123-defa-456789012345",
"members": [...],
"parameter": {
"language": "en",
"department": "customer-service"
},
"tm_create": "2026-02-27 10:00:00.000000",
"tm_update": "2026-02-27 10:05:00.000000",
"tm_delete": "9999-01-01 00:00:00.000000"
}
],
"next_page_token": ""
}
Step 6: Delete a Team
Delete a team when it is no longer needed.
$ curl --location --request DELETE 'https://api.voipbin.net/v1.0/teams/c3d4e5f6-a7b8-9012-cdef-345678901234?token=<YOUR_AUTH_TOKEN>'
Response:
{
"id": "c3d4e5f6-a7b8-9012-cdef-345678901234",
"customer_id": "5e4a0680-804e-11ec-8477-2fea5968d85b",
"name": "Customer Service Team",
"detail": "Routes callers to billing or technical support",
"start_member_id": "d4e5f6a7-b8c9-0123-defa-456789012345",
"members": [...],
"parameter": {
"language": "en",
"department": "customer-service"
},
"tm_create": "2026-02-27 10:00:00.000000",
"tm_update": "2026-02-27 10:05:00.000000",
"tm_delete": "2026-02-27 11:00:00.000000"
}
Note
AI Implementation Hint
Deleting a team does not delete the underlying AI configurations. The AIs referenced by ai_id remain available and can be reused in other teams or standalone flows. To fully clean up, delete the AI configurations separately via DELETE /ais/{ai_id}.
Best Practices
Team Design:
Keep each member focused on a single domain (billing, support, sales). Broad prompts lead to less accurate routing.
Write transition
descriptionfields as explicit conditions, not vague labels. The LLM relies on these to decide when to switch.Design bidirectional transitions for flexibility — allow callers to go back to the receptionist from any specialist.
AI Configuration:
Each member’s AI should have a prompt that includes context about its role within the team. For example:
"You are the billing specialist on the customer service team. A receptionist has already greeted the caller and identified their billing question."Use consistent TTS voices across members for a cohesive caller experience, or deliberately vary them to signal the handoff.
Testing:
Test each AI configuration individually via
POST /callswith an inlineai_talkaction before assembling them into a team.Verify transitions by testing conversations that should trigger each
function_name.
Troubleshooting
- 400 Bad Request:
Cause:
start_member_iddoes not match any member’sidin themembersarray.Fix: Verify that
start_member_idis set to a valid memberid.
- 400 Bad Request:
Cause: A
next_member_idin a transition references a member that does not exist in themembersarray.Fix: Ensure all
next_member_idvalues point to valid memberidvalues within the same team.
- 402 Payment Required:
Cause: Insufficient account balance. Team conversations consume credits for each active member’s LLM, TTS, and STT usage.
Fix: Check balance via
GET /billing-accounts. Top up before retrying.
- 404 Not Found:
Cause: The team UUID does not exist or belongs to a different customer.
Fix: Verify the UUID was obtained from
GET /teamsorPOST /teams.
- AI not switching members:
Cause: The transition
descriptionis too vague for the LLM to match.Fix: Make the description more specific. Example:
"Transfer when the caller mentions billing, invoices, or payments"instead of"Transfer to billing".
- Wrong member activated at start:
Cause:
start_member_idpoints to the wrong member.Fix: Update the team via
PUT /teams/{id}with the correctstart_member_id.