Saltar al contenido principal

Subagentes

Un subagente es una segunda persona especializada sobre el mismo agente: su propio prompt, voz, modelo y herramientas, que toma parte de una llamada y la devuelve cuando termina. El agente asociado al numero de telefono sigue siendo el agente principal durante toda la llamada - conserva el registro de llamada, la grabacion, el webhook y la facturacion - asi que un subagente solo cambia como suena y razona el asistente mientras esta activo.

Los subagentes y las transiciones entre ellos viven bajo /agents/{agent_id}. Todas las rutas aceptan la misma autenticacion que el resto de la API publica: envia tu clave en la cabecera X-API-Key (tambien funciona un JWT Bearer). La URL base es https://api.usevocals.com/api/v1.

Nodos y transiciones

El modelo tiene dos piezas:

  • Un nodo es el agente principal o uno de sus subagentes. El agente principal siempre es un nodo y no necesita fila propia: donde se espera un id, null significa el agente principal.
  • Una transicion es un movimiento en un solo sentido de un nodo a otro nodo del mismo agente, con un disparador que decide cuando se activa.

Cada agente admite hasta 20 subagentes, y cada nodo hasta 20 transiciones salientes. Superar cualquiera de los dos limites devuelve 422 Unprocessable Entity. Ninguna de las dos listas se pagina.

Una misma llamada puede realizar como maximo 10 transiciones, por grande que sea el flujo. Cuando una llamada alcanza ese limite, se informa al nodo activo de que ya no hay mas traspasos disponibles y simplemente sigue atendiendo a quien llama: alcanzar el limite nunca termina una llamada. Lo mismo ocurre cuando un subagente no puede activarse - se elimino despues de iniciarse la llamada, o un proveedor del que depende no esta disponible - en cuyo caso la llamada vuelve al agente principal y continua.

Que puede y que no puede cambiar un subagente

Un subagente solo puede sobrescribir como se comporta el asistente. No puede tocar nada que pertenezca a la llamada completa: el numero de telefono, el proveedor de voz a texto y el idioma, la sensibilidad de respuesta, los limites de duracion y silencio, la deteccion de contestador, la grabacion, el analisis automatico, el webhook ni las variables personalizadas declaradas. Todo eso es del agente principal durante toda la llamada, y no existe campo para sobrescribirlo.

Dejar una sobrescritura sin valor (null) significa "comportate como el agente principal". Un subagente que solo define system_prompt conserva la voz, el modelo y las herramientas del agente principal.

Acceso

El acceso a los subagentes de un agente sigue el permiso de comparticion ya concedido sobre ese agente. El espacio de trabajo propietario tiene acceso completo; un agente compartido con permiso de lectura permite ver subagentes y transiciones pero no modificarlos (403 Forbidden al escribir); un agente compartido con permiso de escritura permite editarlo todo. Un agente que no es tuyo ni esta compartido contigo devuelve 404 Not Found.

La comparticion se concede a una persona, asi que aplica al JWT Bearer del dashboard. Una X-API-Key solo alcanza los agentes de su propio espacio de trabajo.

Esquema del Subagente

SubagentResponse lo devuelven las rutas de listado, obtencion, creacion y actualizacion.

CampoTipoDescripcion
iduuidID del subagente
agent_iduuidID del agente principal propietario
namestringIdentifica al subagente y es el nombre con el que la IA le pasa la llamada. Unico dentro del agente y distinto del nombre del propio agente principal.
system_promptstring | nullPrompt usado mientras este subagente esta activo. null hereda el del agente principal.
llm_provider_iduuid | nullProveedor de modelo de lenguaje a usar. null hereda.
tts_provider_iduuid | nullProveedor de voz a usar. null hereda.
voice_idstring | nullVoz con la que hablar. null hereda.
tts_configobject | nullAjustes de voz, con la misma forma que los del agente. null hereda.
opening_linestring | nullSe dice la primera vez que la persona llega a este subagente en una llamada, y nunca se repite si vuelve.
opening_line_enabledbooleanSi la linea de apertura llega a decirse (por defecto true).
interruptibleboolean | nullSi la persona puede interrumpir. null hereda.
barge_in_sensitivitystring | nullvery_low, low, medium, high o very_high. null hereda.
thinking_cue_enabledboolean | nullSi se reproduce una senal de espera. null hereda.
transfer_enabledboolean | nullSi este subagente puede transferir la llamada a una persona. null hereda.
transfer_destinationsarray | nullDestinos de transferencia a humano, con la misma forma que los del agente, hasta 50. null hereda.
included_integration_idsarray | nullQue integraciones del agente puede usar este subagente. null significa todas, [] ninguna.
included_custom_endpoint_idsarray | nullLo mismo, para endpoints personalizados.
included_knowledge_entry_idsarray | nullLo mismo, para entradas de la base de conocimiento.
entry_checkobject | nullUna comprobacion de entrada - ver abajo.
created_atdatetimeMarca de tiempo de creacion
updated_atdatetimeMarca de tiempo de ultima actualizacion

Comprobacion de entrada

Una comprobacion de entrada es un endpoint personalizado que el subagente llama automaticamente en cuanto se activa, antes de que la persona diga nada. Su resultado puede disparar una transicion, que es como un flujo enruta a partir de un hecho ("este cliente tiene una factura vencida") y no de lo que la persona dice.

{
"custom_endpoint_id": "3f1c9b7e-2a4d-4f88-9b0e-6d5c4a2b1e70",
"arguments": { "invoice_number": "4711" }
}

El endpoint debe pertenecer al mismo agente y ser del agente completo o estar acotado a este subagente. Se ejecuta con su propio tiempo de espera configurado, no se reintenta, y un fallo simplemente no dispara ninguna transicion: la llamada continua.

Herramientas y fuentes acotadas a un nodo

Un endpoint personalizado o una entrada de la base de conocimiento se pueden asociar a un unico subagente en lugar de a todo el agente enviando subagent_id al crearlos - consulta Endpoints Personalizados y Base de Conocimiento. Las filas acotadas cuentan para los mismos limites por agente. Una entrada de conocimiento acotada a un nodo solo se consulta mientras responde su subagente; la recuperacion del agente principal nunca la ve.

Esquema de la Transicion

CampoTipoDescripcion
iduuidID de la transicion
agent_iduuidID del agente principal propietario
source_subagent_iduuid | nullNodo del que sale la transicion. null es el agente principal.
target_subagent_iduuid | nullNodo al que entra la transicion. null es el agente principal.
trigger_typestringvariable_match, entry_check_match o model_judgement
trigger_configobjectLas claves dependen de trigger_type - ver abajo
positionintegerOrden de evaluacion dentro del nodo origen, de menor a mayor
fire_countintegerCuantas veces se ha disparado esta transicion en todas las llamadas
last_fired_atdatetime | nullCuando se disparo por ultima vez, null si nunca lo hizo
created_atdatetimeMarca de tiempo de creacion
updated_atdatetimeMarca de tiempo de ultima actualizacion

Origen y destino deben ser distintos, y ambos deben ser nodos del mismo agente: un subagente de otro agente se rechaza con 422.

Tipos de disparador

trigger_typetrigger_configSe dispara cuando
variable_match{"variable": "language", "value": "es"}Una variable de la llamada es igual al valor
entry_check_match{"field": "status", "operator": "equals", "value": "200"}El resultado de la comprobacion de entrada del nodo origen coincide. field es status o body, operator es equals o contains.
model_judgement{"condition": "la persona quiere pagar una factura"}La IA juzga cierta la condicion en lenguaje natural, con el mismo estilo que una condicion de transferencia a humano

Los disparadores deterministas se evaluan primero, por orden de position; el juicio del modelo es el recurso cuando ninguno se dispara. Una transicion entry_check_match necesita que su nodo origen declare un entry_check, de lo contrario crearla devuelve 422.

Que oye la persona que llama

Un traspaso esta pensado para ser inaudible. El subagente que entrega dice una frase breve con su propia voz - la termina antes de que nada cambie - y el subagente que recibe dice entonces su linea de apertura, si tiene una y es la primera vez que la persona llega a el en esa llamada. No se dice nada mas: nunca se le cuenta a la persona que ha habido un traspaso, nunca oye el nombre de un destino y nunca tiene que repetir algo ya tratado. Toda la conversacion hasta ese momento le acompana, junto con una nota breve del subagente que entrega.

Todo lo que la persona puede percibir cambia en ese punto: la voz, el modelo de lenguaje, las herramientas, la base de conocimiento, los destinos de escalado y el prompt. Nada de la llamada en si cambia. La linea sigue abierta, la transcripcion de voz sigue funcionando con los ajustes del agente principal y no se realiza ninguna operacion telefonica, que es lo que lo diferencia de transferir a una persona, donde la llamada sale realmente de VOCALS. Ambas funcionan en el mismo agente, y un subagente tambien puede escalar a una persona.

Despues de la llamada

Una llamada que uso subagentes produce un unico registro de llamada, una grabacion, una transcripcion y un webhook, todos pertenecientes al agente principal. Lo que hizo cada subagente se registra ademas:

  • node_journey y node_usage en la respuesta de detalle de la llamada: quien atendio cada parte, y que uso y coste tuvo cada uno. Ver Llamadas.
  • node_id y node_name en cada turno de la transcripcion.
  • nodes en la carga util del webhook call.completed, con el mismo recorrido.
  • fire_count y last_fired_at en cada transicion, para ver que rutas toman realmente las personas que llaman.

Endpoints

MetodoRutaProposito
GET/agents/{agent_id}/subagentsLista los subagentes del agente (mas antiguos primero)
POST/agents/{agent_id}/subagentsCrea un subagente
GET/agents/{agent_id}/subagents/{subagent_id}Obtiene un subagente
PUT/agents/{agent_id}/subagents/{subagent_id}Actualiza un subagente (parcial: envia solo lo que cambia)
DELETE/agents/{agent_id}/subagents/{subagent_id}Elimina un subagente
GET/agents/{agent_id}/transitionsObtiene el flujo completo: todos los nodos y todas las transiciones
POST/agents/{agent_id}/transitionsCrea una transicion
PUT/agents/{agent_id}/transitions/{transition_id}Actualiza una transicion
DELETE/agents/{agent_id}/transitions/{transition_id}Elimina una transicion

Listar Subagentes

GET /agents/{agent_id}/subagents
curl -H "X-API-Key: voc_a1b2c3d4e5f6..." \
https://api.usevocals.com/api/v1/agents/{agent_id}/subagents

Respuesta

[
{
"id": "8c2e5a10-99f4-4c1e-9a6b-2d7f0e4b8a13",
"agent_id": "9f8b7c6d-1234-4a5b-9c8d-abcdef012345",
"name": "billing",
"system_prompt": "Gestionas facturas y pagos. Se preciso con los importes.",
"llm_provider_id": null,
"tts_provider_id": null,
"voice_id": null,
"tts_config": null,
"opening_line": "Facturacion, puedo ayudarte con eso.",
"opening_line_enabled": true,
"interruptible": null,
"barge_in_sensitivity": null,
"thinking_cue_enabled": null,
"transfer_enabled": null,
"transfer_destinations": null,
"included_integration_ids": null,
"included_custom_endpoint_ids": null,
"included_knowledge_entry_ids": null,
"entry_check": null,
"created_at": "2026-08-01T09:12:04Z",
"updated_at": "2026-08-01T09:12:04Z"
}
]

Crear Subagente

POST /agents/{agent_id}/subagents

Solo name es obligatorio. Todos los demas campos son sobrescrituras que puedes omitir.

curl -X POST \
-H "X-API-Key: voc_a1b2c3d4e5f6..." \
-H "Content-Type: application/json" \
-d '{
"name": "billing",
"system_prompt": "Gestionas facturas y pagos. Se preciso con los importes.",
"opening_line": "Facturacion, puedo ayudarte con eso.",
"barge_in_sensitivity": "high"
}' \
https://api.usevocals.com/api/v1/agents/{agent_id}/subagents

Devuelve 201 Created con el subagente almacenado.

Actualizar Subagente

PUT /agents/{agent_id}/subagents/{subagent_id}

Parcial: solo cambian los campos que envias. Enviar un campo como null elimina esa sobrescritura, de modo que el subagente vuelve a heredar el valor del agente principal.

curl -X PUT \
-H "X-API-Key: voc_a1b2c3d4e5f6..." \
-H "Content-Type: application/json" \
-d '{"voice_id": null}' \
https://api.usevocals.com/api/v1/agents/{agent_id}/subagents/{subagent_id}

Eliminar Subagente

DELETE /agents/{agent_id}/subagents/{subagent_id}

Devuelve 204 No Content. Las llamadas pasadas conservan su registro del subagente, de modo que las transcripciones y analiticas historicas siguen atribuidas a el.

Obtener el Flujo

GET /agents/{agent_id}/transitions

Devuelve el flujo completo en una sola llamada: todos los nodos, incluido el agente principal, y todas las transiciones entre ellos. tts_vendor es el proveedor de voz con el que cada nodo habla realmente una vez resuelta la herencia, de modo que puedes detectar un traspaso que cambia de proveedor de voz a mitad de llamada.

curl -H "X-API-Key: voc_a1b2c3d4e5f6..." \
https://api.usevocals.com/api/v1/agents/{agent_id}/transitions

Respuesta

{
"nodes": [
{ "node_id": null, "name": "Recepcion", "tts_vendor": "elevenlabs" },
{
"node_id": "8c2e5a10-99f4-4c1e-9a6b-2d7f0e4b8a13",
"name": "billing",
"tts_vendor": "elevenlabs"
}
],
"transitions": [
{
"id": "b7d1f0a2-3c44-4e91-8a0d-1f2e3d4c5b6a",
"agent_id": "9f8b7c6d-1234-4a5b-9c8d-abcdef012345",
"source_subagent_id": null,
"target_subagent_id": "8c2e5a10-99f4-4c1e-9a6b-2d7f0e4b8a13",
"trigger_type": "model_judgement",
"trigger_config": { "condition": "la persona quiere pagar una factura" },
"position": 0,
"fire_count": 42,
"last_fired_at": "2026-08-28T16:03:51Z",
"created_at": "2026-08-01T09:14:22Z",
"updated_at": "2026-08-01T09:14:22Z"
}
]
}

fire_count y last_fired_at son lo que indica que rutas toman realmente las personas que llaman, y que transicion no se dispara nunca y conviene reformular o eliminar.

Crear Transicion

POST /agents/{agent_id}/transitions
curl -X POST \
-H "X-API-Key: voc_a1b2c3d4e5f6..." \
-H "Content-Type: application/json" \
-d '{
"source_subagent_id": null,
"target_subagent_id": "8c2e5a10-99f4-4c1e-9a6b-2d7f0e4b8a13",
"trigger_type": "model_judgement",
"trigger_config": { "condition": "la persona quiere pagar una factura" },
"position": 0
}' \
https://api.usevocals.com/api/v1/agents/{agent_id}/transitions

Devuelve 201 Created. Para permitir el regreso, anade la transicion espejo con source_subagent_id apuntando al subagente y target_subagent_id a null.

Actualizar Transicion

PUT /agents/{agent_id}/transitions/{transition_id}

Parcial, y despues se vuelve a comprobar la transicion entera: cambiar solo trigger_type sigue validando el disparador contra el nodo origen almacenado.

Eliminar Transicion

DELETE /agents/{agent_id}/transitions/{transition_id}

Devuelve 204 No Content. El historial de disparos permanece en las llamadas que lo registraron.

Errores

EstadoSignificado
403 ForbiddenEl agente esta compartido contigo solo en lectura e intentaste escribir
404 Not FoundEl agente no es tuyo ni esta compartido contigo, o el subagente/transicion no existe
422 Unprocessable EntityFallo la validacion: nombre duplicado, nombre igual al del agente principal, limite alcanzado, un nodo de otro agente o un disparador mal formado. El motivo esta en detail.