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

# Función personalizada

> Conecta tu propio endpoint HTTP para que el agente de voz consulte o escriba en tus sistemas a media llamada.

<Note>
  La función personalizada le da al agente una capacidad que no trae de fábrica:
  consultar o escribir en <strong>tus</strong> sistemas mientras habla con la
  persona. Tú publicas un endpoint HTTP; el agente decide cuándo llamarlo, con
  qué datos, y usa la respuesta para continuar la conversación en la misma
  llamada.
</Note>

## Cómo funciona

La función no se ejecuta en un momento fijo del guion. Se ejecuta cuando el
agente reconoce que la necesita, con base en la descripción que escribes al
configurarla. El ciclo completo ocurre dentro de la llamada, sin colgar y sin
transferir:

1. La persona dice algo que corresponde a la función: «quiero saber cómo va mi pedido».
2. El agente **extrae de la conversación** los datos que tu función pide —número
   de pedido, teléfono, RFC— según el esquema de parámetros que declaraste. Si le
   falta un dato, lo pregunta antes de llamar.
3. La plataforma envía la petición HTTP a tu URL con esos datos, y espera tu respuesta.
4. El agente recibe el cuerpo de tu respuesta y sigue hablando con esa
   información: la dice en voz alta, la usa para decidir el siguiente paso, o la
   guarda como variable para usarla más adelante en la misma llamada.

<Warning>
  Mientras tu endpoint responde, **hay una persona esperando en la línea**. Ese
  es el criterio que gobierna todo lo demás: la función se diseña como una
  consulta de voz, no como un proceso por lotes.
</Warning>

## El contrato

| La plataforma envía                                                                                                                                                                                                                     | Tu servicio devuelve                                                                                                                                                                                                    |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Una petición HTTP al método y la URL que configuraste, con tus encabezados fijos y tus parámetros de query. El cuerpo lleva los datos que el agente recolectó en la conversación, con los nombres y tipos que declaraste en el esquema. | Un código 2xx y un cuerpo JSON **plano y corto**. Ese cuerpo es lo que el agente va a leer: si le devuelves un objeto anidado de cincuenta campos, va a tener que resumirlo sobre la marcha, y ahí se pierde precisión. |

Por defecto esos datos llegan **en la raíz** del cuerpo. Si lo configuras al
revés, llegan anidados bajo `args`, acompañados del contexto de la llamada.

Devuelve la frase que quieres que se diga, ya resuelta: «Tu pedido va en camino y
llega el jueves» funciona mejor que `status: 3`.

```http theme={null}
POST https://api.tu-empresa.mx/agentes/estatus-pedido
Authorization: Bearer <tu-token>
Content-Type: application/json

{ "numero_pedido": "MX-99413", "telefono": "+525512345678" }
```

```json theme={null}
200 OK

{
  "encontrado": true,
  "estatus": "en reparto",
  "mensaje_para_el_cliente": "Tu pedido va en camino y llega el jueves",
  "fecha_entrega": "2026-08-27"
}
```

<Info>
  **Buena práctica.** Incluye siempre un campo que distinga «no encontré nada» de
  «falló la consulta» —como el `encontrado` del ejemplo—. Son dos conversaciones
  distintas: en la primera el agente pide verificar el dato, en la segunda ofrece
  un canal alterno.
</Info>

## Configuración

Cada función personalizada es una conexión propia del agente. Puedes tener
varias en el mismo agente —una para consultar, otra para registrar— y cada una se
configura por separado.

| Ajuste                         | Qué controla                                                                                                                                                                           | Valor por defecto                  |
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- |
| Nombre de la función           | Cómo se identifica la función ante el agente. Se normaliza automáticamente a minúsculas, sin acentos ni espacios (sólo letras, números, `_` y `-`), con un máximo de 64 caracteres.    | Derivado del nombre de la conexión |
| Cuándo usarla                  | La descripción que lee el agente para decidir si esta función aplica. **Es el ajuste que más determina el comportamiento**: si es vaga, el agente la llama de más o no la llama nunca. | —                                  |
| Datos que pide                 | El esquema de los parámetros: nombre, tipo, descripción y cuáles son obligatorios. El agente pregunta lo que falte antes de ejecutar.                                                  | Sin parámetros                     |
| URL y método                   | El destino de la petición. Métodos disponibles: `GET`, `POST`, `PUT`, `PATCH`, `DELETE`.                                                                                               | `POST`                             |
| Encabezados                    | Pares fijos que viajan en cada petición. Es el lugar de tu credencial de autenticación.                                                                                                | Ninguno                            |
| Parámetros de query            | Pares fijos que se agregan a la URL, útiles para versión de API o identificador de canal.                                                                                              | Ninguno                            |
| Formato del cuerpo             | JSON o formulario.                                                                                                                                                                     | Formulario                         |
| Tiempo máximo de espera        | Cuánto espera la plataforma tu respuesta antes de darla por perdida. Admite de 1 segundo a 10 minutos, pero **el rango sano para voz es 2 a 5 segundos**.                              | 2 minutos                          |
| Hablar durante la ejecución    | Que el agente diga una frase de espera mientras tu endpoint responde. Enciéndelo si tu respuesta pasa de dos segundos; el silencio en una llamada se percibe como llamada caída.       | Apagado                            |
| Hablar después de la ejecución | Que el agente comunique el resultado en voz alta. Apágalo sólo cuando la función es un registro silencioso y no hay nada que informar.                                                 | Encendido                          |
| Variables de respuesta         | Nombres a los que se asignan campos de tu respuesta, para reutilizarlos después en la misma conversación —en otra función, o en el guion del agente—.                                  | Ninguna                            |

<Warning>
  **Cuándo entra en vigor.** Conectar o modificar una función personalizada no
  cambia el agente que ya está atendiendo. Los cambios se aplican cuando se
  publica una **nueva versión** del agente. Si probaste un ajuste y no ves
  diferencia en las llamadas, ese es el primer punto a revisar.
</Warning>

### Conectarla por API

La configuración vive en `metadata.connectionConfig` de la conexión. Los nombres
de los campos son los de la tabla anterior, en camelCase:

```bash theme={null}
curl --request POST \
  --url "$API_BASE_URL/v1/tools/custom.http/connections" \
  --header "X-API-Key: $API_KEY" \
  --header "X-Workspace-Id: $WORKSPACE_ID" \
  --header "Content-Type: application/json" \
  --data '{
    "agentId": "38f62697-0f4b-49bc-8a0c-67256f5af6ff",
    "connectionKey": "estatus_pedido",
    "descriptionUsage": "Úsala cuando la persona pregunte por el estado de un pedido que ya hizo. No la uses para cotizaciones ni para pedidos que aún no existen.",
    "metadata": {
      "connectionConfig": {
        "method": "POST",
        "url": "https://api.tu-empresa.mx/agentes/estatus-pedido",
        "parameterType": "json",
        "timeoutMs": 4000,
        "headers": { "Authorization": "Bearer <tu-token>" },
        "queryParams": { "v": "2" },
        "parameters": {
          "type": "object",
          "properties": {
            "numero_pedido": {
              "type": "string",
              "description": "Número de pedido que dicte el cliente, con el formato MX-00000."
            }
          },
          "required": ["numero_pedido"]
        },
        "argsAtRoot": true,
        "speakDuringExecution": true,
        "speakAfterExecution": true,
        "responseVariables": { "fecha_entrega_pedido": "fecha_entrega" }
      }
    }
  }'
```

Requiere el scope `tools:connections:write`. Una configuración inválida responde `400` con el
detalle del campo que falla, así que un error de captura no se descubre en la
primera llamada.

## Requisitos del endpoint

* **Accesible desde internet, por HTTPS.** Se aceptan sólo direcciones `http` y
  `https`, y se rechazan destinos locales (`localhost`, `127.0.0.1`, `0.0.0.0`).
  Un endpoint que sólo vive en tu red interna no es alcanzable.
* **Autenticación por encabezado.** Token, API key o Basic: lo que uses va en los
  encabezados de la conexión. Nunca en la URL ni en los parámetros de query, que
  quedan registrados.
* **Sin lista blanca por IP.** La petición sale de la infraestructura de voz de la
  plataforma y su dirección de origen no es fija. Autoriza por credencial, no por IP.
* **Idempotente.** El agente puede llamar la misma función más de una vez en una
  conversación —la persona se corrige, repite el dato, pide reconfirmar—. Si la
  función escribe algo (crea un ticket, registra una cita), pide en el esquema un
  identificador propio y descarta duplicados con él.
* **Rápido y predecible.** Si tu operación real tarda minutos, no la ejecutes
  dentro de la llamada: acusa recibo en segundos, procesa después, y avísale al
  cliente por otro canal.
* **En `GET`, los datos viajan en la URL.** No lleva cuerpo.

## Cuando algo falla

**La llamada no se cae.** Si tu endpoint devuelve un error, tarda más del tiempo
configurado o no responde, la conversación continúa: el agente recibe el
resultado fallido y sigue con lo que su guion le indique para ese caso.

Por eso el plan B es parte del diseño de la función, no un detalle posterior:
define en el guion del agente qué debe decir cuando la consulta no está
disponible —tomar el dato y prometer seguimiento, ofrecer transferir con un
asesor, agendar un callback—. Sin esa instrucción, el agente improvisa.

| Lo que observas                                   | Causa más frecuente                                                                                                                  |
| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| El agente nunca llama la función                  | La descripción de «cuándo usarla» no coincide con lo que la persona dice, o el cambio no se publicó en una versión nueva del agente. |
| La llama cuando no debería                        | La descripción es demasiado amplia. Acótala nombrando explícitamente los casos que no son suyos.                                     |
| Llega la petición con datos vacíos                | El esquema no declara esos campos como obligatorios, o su descripción no le dice al agente qué preguntar.                            |
| Llegan dos peticiones iguales seguidas            | La persona repitió o corrigió el dato. Es comportamiento esperado: resuélvelo con idempotencia.                                      |
| Silencio de varios segundos antes de la respuesta | Tu endpoint tarda. Baja el tiempo de respuesta y enciende la frase de espera.                                                        |
| `401` o `403` en tu bitácora                      | Encabezado de autenticación mal configurado, credencial rotada, o una restricción por IP en tu servidor.                             |
| La configuración no se guarda                     | URL inválida o no permitida, método no soportado, o esquema de parámetros mal formado. El mensaje de error indica el campo.          |
| El agente dice el resultado en desorden           | La respuesta es demasiado grande o anidada. Devuelve el mensaje ya redactado.                                                        |

## Antes de salir a producción

* El endpoint responde por HTTPS desde internet y devuelve 2xx con JSON.
* Responde en menos de tres segundos con datos reales, no sólo en el ambiente de pruebas.
* La credencial va en un encabezado y está rotada para este uso.
* La operación es idempotente, o descarta duplicados con un identificador propio.
* El esquema declara como obligatorio todo dato sin el cual la consulta no tiene sentido.
* La respuesta incluye un mensaje listo para decirse en voz alta.
* Distingue «no encontrado» de «error».
* El guion del agente tiene un plan B para cuando la función no está disponible.
* Se publicó una versión nueva del agente y se validó con una llamada de prueba de punta a punta.
