Sign inGet Started

Crear una llamada de voz

Warning: Voice sequences are in preview. Steps, entry data, and the sequence definition format can change in ways that break existing sequences and API requests.

Usa POST /v1/voice/calls para llamar a un número de teléfono e iniciar una secuencia publicada, o una definición de secuencia enviada con la solicitud, cuando el destinatario conteste. La solicitud realiza una llamada real; se aplican los cargos habituales de llamada.

Vista previa de CLI y MCP: Estas interfaces requieren un cliente compatible. Comprueba que tu servidor MCP exponga voice_calls_create, o ejecuta bird voice --help para listar los comandos de tu CLI. Comprueba si hay versiones más recientes con bird update --check y consulta Instalación de CLI. Si la herramienta o el comando no está disponible, usa la API HTTP o los SDK.

En la vista previa, CLI y MCP preparan la misma llamada para que una persona la revise y ejecute en el navegador. El agente recibe el resultado de aceptación registrado después de que la persona ejecuta la solicitud.

Antes de empezar

Prepara estos recursos en el mismo espacio de trabajo:

  • Una secuencia para ejecutar: una secuencia habilitada y no archivada con una publicación activa creada en el panel, o una definición completa enviada con la solicitud.
  • Una clave API para solicitudes HTTP, o un inicio de sesión OAuth para CLI y MCP, con permisos de voice_management:write y voice:write.
  • Un número de llamada que el espacio de trabajo pueda presentar, como un identificador de llamada propio o verificado, y un país de destino habilitado. Usa preferiblemente un número del país del destinatario: algunas redes móviles rechazan una llamada que presenta un identificador de llamada extranjero.
  • Un destinatario que controles para la primera llamada.

El objeto sequence acepta exactamente uno de sequence.id o sequence.definition. Ambos también necesitan entry_node_id, el paso Start call donde comienza la llamada, y trigger_data, un objeto que coincida con el esquema de datos de esa entrada. Usa {} cuando la entrada acepte datos vacíos. La referencia de Create Call documenta los límites de solicitud y el tiempo de espera de timbre opcional.

Llamar a una secuencia creada en el panel

Usa sequence.id para ejecutar una secuencia que creaste y publicaste en el panel. Create Call siempre ejecuta su publicación activa.

  1. Abre la secuencia en Sequences.
  2. En How to run this sequence, selecciona More details junto a Create a call.
  3. Si la secuencia tiene varias entradas, elige el Call trigger con el que iniciar.
  4. Copia la solicitud. Contiene el ID de secuencia y el ID de entrada.

Guarda el cuerpo de la solicitud como call.json, reemplazando los números de ejemplo con los tuyos:

Ejemplo de código
{
  "from": "+12025550100",
  "to": "+12025550101",
  "sequence": {
    "id": "YOUR_SEQUENCE_ID",
    "entry_node_id": "YOUR_ENTRY_NODE_ID",
    "trigger_data": {}
  }
}

Rellena trigger_data con los campos que la entrada declara, incluidos objetos anidados y arrays. Create Call no acepta versiones históricas, borradores ni modo de prueba. Para probar un borrador guardado, usa los controles de Realizar una llamada del panel.

Ejecutar una secuencia en línea

Usa sequence.definition para enviar una secuencia completa con la llamada. Bird la ejecuta una vez y no la guarda, por lo que la llamada no tiene ID de secuencia. Una definición en línea es adecuada para flujos que tu aplicación genera por llamada.

Una definición en línea debe superar las mismas comprobaciones que la publicación de una secuencia. Su ejecución puede ejecutar como máximo 16 comandos, incluidos los prompts de recopilación; una llamada que necesite un 17.º termina con el error de traza call_limit. La referencia de nodos enumera cada paso que puedes usar, con sus campos y resultados. Para partir de un flujo funcional, constrúyelo y publícalo en el panel, abre la secuencia y selecciona Copy JSON en Definition JSON bajo Published version.

Este call.json pide al destinatario que pulse 1 para horario de atención o 2 para indicaciones. El silencio y cualquier otra tecla terminan la ejecución con sus propias razones de salida:

Ejemplo de código
{
  "from": "+12025550100",
  "to": "+12025550101",
  "sequence": {
    "entry_node_id": "start",
    "trigger_data": {},
    "definition": {
      "schema_version": 1,
      "expression_environment": "bird.cel.v1",
      "nodes": [
        {
          "id": "start",
          "type": "trigger.start_call",
          "type_version": 1,
          "config": {},
          "input": {},
          "connections": { "event": { "node_id": "menu", "port": "input" } }
        },
        {
          "id": "menu",
          "type": "voice.gather",
          "type_version": 1,
          "config": {},
          "input": {
            "prompts": [
              {
                "type": "say",
                "text": "Press 1 for opening hours, or 2 for directions.",
                "language": "en"
              }
            ],
            "max_digits": 1,
            "timeout_seconds": 5,
            "inter_digit_timeout_seconds": 2,
            "finish_on_key": "#",
            "private": false,
            "matches": { "hours": "1", "directions": "2" }
          },
          "connections": {
            "hours": { "node_id": "hours", "port": "input" },
            "directions": { "node_id": "directions", "port": "input" },
            "timeout": { "node_id": "no_input", "port": "input" },
            "fallback": { "node_id": "other_input", "port": "input" }
          }
        },
        {
          "id": "hours",
          "type": "voice.say",
          "type_version": 1,
          "config": {},
          "input": { "text": "We are open Monday through Friday, nine to five.", "language": "en" },
          "connections": { "next": { "node_id": "done", "port": "input" } }
        },
        {
          "id": "directions",
          "type": "voice.say",
          "type_version": 1,
          "config": {},
          "input": {
            "text": "Find directions on your appointment confirmation.",
            "language": "en"
          },
          "connections": { "next": { "node_id": "done", "port": "input" } }
        },
        {
          "id": "done",
          "type": "logic.exit",
          "type_version": 1,
          "config": { "status": "succeeded", "reason": "information_played" },
          "input": { "output": {} }
        },
        {
          "id": "no_input",
          "type": "logic.exit",
          "type_version": 1,
          "config": { "status": "succeeded", "reason": "no_input" },
          "input": { "output": {} }
        },
        {
          "id": "other_input",
          "type": "logic.exit",
          "type_version": 1,
          "config": { "status": "succeeded", "reason": "unrecognized_input" },
          "input": { "output": {} }
        }
      ]
    }
  }
}

El connections de cada nodo asigna un resultado al siguiente nodo. matches del menú nombra sus opciones, y connections usa los mismos nombres junto con los resultados integrados timeout y fallback.

Personalizar una secuencia en línea

Declara los campos que envías en data_schema de la entrada y luego léelos como trigger.data.<field> en un valor $expr. Esta llamada saluda al destinatario por su nombre y confirma o señala su cita:

Ejemplo de código
{
  "from": "+12025550100",
  "to": "+12025550101",
  "sequence": {
    "entry_node_id": "start",
    "trigger_data": {
      "appointment_id": "apt_2048",
      "customer_name": "Sam",
      "appointment_time": "Tuesday at 10 AM"
    },
    "definition": {
      "schema_version": 1,
      "expression_environment": "bird.cel.v1",
      "nodes": [
        {
          "id": "start",
          "type": "trigger.start_call",
          "type_version": 1,
          "config": {
            "data_schema": {
              "type": "object",
              "additionalProperties": false,
              "required": ["appointment_id", "customer_name", "appointment_time"],
              "properties": {
                "appointment_id": { "type": "string", "minLength": 1 },
                "customer_name": { "type": "string", "minLength": 1 },
                "appointment_time": { "type": "string", "minLength": 1 }
              }
            }
          },
          "input": {},
          "connections": { "event": { "node_id": "confirm_menu", "port": "input" } }
        },
        {
          "id": "confirm_menu",
          "type": "voice.gather",
          "type_version": 1,
          "config": {},
          "input": {
            "prompts": [
              {
                "type": "say",
                "text": {
                  "$template": [
                    "Hello ",
                    { "$expr": "trigger.data.customer_name" },
                    ". Press 1 to confirm your appointment on ",
                    { "$expr": "trigger.data.appointment_time" },
                    ", or 2 if you need help."
                  ]
                },
                "language": "en"
              }
            ],
            "max_digits": 1,
            "timeout_seconds": 7,
            "inter_digit_timeout_seconds": 2,
            "finish_on_key": null,
            "private": false,
            "matches": { "confirm": "1", "help": "2" }
          },
          "connections": {
            "confirm": { "node_id": "confirmed", "port": "input" },
            "help": { "node_id": "help_requested", "port": "input" },
            "timeout": { "node_id": "no_response", "port": "input" },
            "fallback": { "node_id": "no_response", "port": "input" }
          }
        },
        {
          "id": "confirmed",
          "type": "logic.exit",
          "type_version": 1,
          "config": { "status": "succeeded", "reason": "appointment_confirmed" },
          "input": {
            "output": { "appointment_id": { "$expr": "trigger.data.appointment_id" } }
          }
        },
        {
          "id": "help_requested",
          "type": "logic.exit",
          "type_version": 1,
          "config": { "status": "succeeded", "reason": "appointment_help_requested" },
          "input": {
            "output": { "appointment_id": { "$expr": "trigger.data.appointment_id" } }
          }
        },
        {
          "id": "no_response",
          "type": "logic.exit",
          "type_version": 1,
          "config": { "status": "failed", "reason": "appointment_no_response" },
          "input": {
            "output": { "appointment_id": { "$expr": "trigger.data.appointment_id" } }
          }
        }
      ]
    }
  }
}

status y reason de cada salida separan una confirmación, una solicitud de ayuda y la ausencia de respuesta. Un objeto trigger_data que no coincide con data_schema falla la validación, con su ubicación en /sequence/trigger_data, y no se realiza ninguna llamada.

Envía la solicitud

Elige uno de los métodos de solicitud a continuación para el call.json que guardaste.

Elige una clave de idempotencia única y nueva una sola vez para esta llamada prevista. Conserva esa clave y la entrada original para reintentos o recuperación de confirmación. Elige otra clave cuando quieras realizar una nueva llamada independiente, después de resolver cualquier resultado desconocido de la llamada original.

Para los ejemplos de shell, establece IDEMPOTENCY_KEY con el valor que elijas antes de enviar. Los ejemplos se detienen si no está definido o está vacío; no generan otra clave al repetirse.

Para HTTP, establece BIRD_API_KEY con tu clave y BIRD_API_URL con su URL base regional, como https://eu1.platform.bird.com para una clave eu1, y luego envía la solicitud:

Ejemplo de código
curl --request POST "$BIRD_API_URL/v1/voice/calls" \
  --header "Authorization: Bearer $BIRD_API_KEY" \
  --header 'Content-Type: application/json' \
  --header "Idempotency-Key: ${IDEMPOTENCY_KEY:?Set IDEMPOTENCY_KEY to the saved key for this intended call}" \
  --data-binary @call.json

Para la vista previa de CLI, inicia sesión con ambos permisos de escritura y prepara la llamada usando el mismo archivo:

Ejemplo de código
bird auth login --scope voice_management:write --scope voice:write
bird voice calls create --body-file call.json \
  --idempotency-key "${IDEMPOTENCY_KEY:?Set IDEMPOTENCY_KEY to the saved key for this intended call}"

El comando imprime un enlace de revisión en el navegador y espera a que se complete. Abre el enlace, verifica el llamante, el destinatario, la secuencia y los datos de entrada, y ejecuta la solicitud tú mismo. Preparar la solicitud no realiza la llamada. Añade --dry-run para inspeccionar la solicitud CLI sin crear una confirmación. Si la confirmación expira, se cancela o termina sin un resultado registrado, el comando sale con 5; sigue la guía de reintentos antes de hacer otra solicitud.

Para la vista previa de MCP, llama a voice_calls_create con los campos de call.json y un idempotency_key obligatorio. Reemplaza <unique-key-for-this-request-reuse-for-retries> con la clave que elijas:

Ejemplo de código
{
  "from": "+12025550100",
  "to": "+12025550101",
  "sequence": {
    "id": "YOUR_SEQUENCE_ID",
    "entry_node_id": "YOUR_ENTRY_NODE_ID",
    "trigger_data": {}
  },
  "idempotency_key": "<unique-key-for-this-request-reuse-for-retries>"
}

Sigue el enlace de revisión en el navegador devuelto para ejecutar la solicitud. En el endpoint dinámico MCP, selecciona voice_calls_create a través de execute. El consentimiento OAuth otorga permisos del espacio de trabajo; la revisión en el navegador ejecuta esta llamada específica.

Una respuesta 202 Accepted confirma la admisión. La secuencia comienza después de que el destinatario contesta. Publicar una versión más nueva después de la aceptación no cambia la definición seleccionada ni los datos de entrada de esta llamada.

Lee el resultado de aceptación

Conserva id, initial_leg_id y sequence.run_id de la respuesta para correlación. El id de nivel superior identifica la llamada a través de sus tramos; initial_leg_id identifica su primer tramo.

La respuesta es una instantánea de aceptación inmutable. Sus started_at y ended_at son null, los booleanos de observación son false y parties está vacío. Estos campos describen la aceptación, por lo que no se convierten en un informe de estado en tiempo real cuando repites la solicitud.

Abre Runs de la secuencia para inspeccionar el progreso. Una llamada en línea no pertenece a ninguna secuencia, así que sigue su tramo en su lugar; si falla antes de que su tramo se registre, aún no hay forma de inspeccionarla. Una vez que exista el registro de tramo, usa GET /v1/voice/legs/{leg_id} con initial_leg_id, o inspecciona el registro de llamadas. Leer tramos requiere el permiso voice:read, que voice:write incluye.

Un tramo con status rejected fue rechazado antes de conectarse, por lo que su secuencia no se ejecutó. Sin un motivo de rechazo, el extremo remoto declinó la llamada; consulta Llamadas rechazadas.

Con CLI, bird voice calls get YOUR_CALL_ID muestra la llamada y sus participantes. bird voice legs trace YOUR_LEG_ID muestra qué pasos se ejecutaron, los dígitos recopilados salvo que el gather sea privado, y el estado y motivo de salida. La traza está disponible poco después de que la llamada termine; hasta entonces el comando devuelve un error, así que reintenta. La secuencia de un tramo rechazado nunca se ejecutó, por lo que puede no tener traza.

La aceptación no garantiza la marcación, una respuesta ni un registro de llamada legible. Una llamada que falla antes del registro puede aparecer en el historial de ejecución sin un registro de tramo. Una llamada contestada tampoco confirma que la secuencia completó su tarea de negocio prevista.

Manejo de errores y reintentos

Para solicitudes directas HTTP, la idempotencia es opcional. Sin clave, cada solicitud acepta un nuevo intento de llamada. Los SDK generan una clave para reintentos automáticos. Para proteger reintentos entre llamadas independientes o solicitudes directas HTTP, proporciona una clave en el primer intento y reutilízala con los bytes exactos de la solicitud original. Consulta la guía de idempotencia.

Una repetición idéntica dentro de tres horas devuelve la aceptación original y Idempotency-Replay: true. Una entrada modificada con esa clave devuelve 409. La autorización y el permiso de número de llamada se verifican de nuevo en la repetición. Después de la ventana de repetición, la clave puede admitir una nueva llamada, así que reconcilia el resultado original antes de reenviar.

Para CLI y MCP, proporciona la clave de idempotencia en el primer intento. Repetir la misma solicitud y clave con la misma concesión OAuth devuelve la confirmación existente mientras su registro se conserva. Conserva la entrada original y el ID de confirmación. Cambiar la clave puede preparar otra llamada facturable.

Si el comando CLI se interrumpe, reanuda con la entrada original, la clave y el ID de confirmación devuelto:

Ejemplo de código
bird voice calls create --body-file call.json \
  --idempotency-key "${IDEMPOTENCY_KEY:?Set IDEMPOTENCY_KEY to the saved key for this intended call}" \
  --confirmation-id YOUR_CONFIRMATION_ID

Para MCP, repite los argumentos originales de la herramienta, incluido el mismo idempotency_key, junto con el estado de solicitud devuelto. El estado identifica la confirmación y no reemplaza esos argumentos. Alternativamente, repite la misma herramienta y argumentos con el ID devuelto en los metadatos de solicitud bird/confirmation-id. Con MCP dinámico, repite la misma solicitud execute y coloca esos metadatos en ella. Reanudar lee la confirmación original y devuelve su resultado registrado cuando se completa.

Una confirmación de Create Call expira después de 90 minutos. Una confirmación pending o expired sin resultado no demuestra que la llamada nunca se realizó. Inspecciona la ejecución de la secuencia original y cualquier registro de tramo antes de decidir realizar otra llamada; no crees una clave nueva para resolver un resultado desconocido. Una confirmación completada con un resultado 202 demuestra la aceptación, así que continúa con las comprobaciones de aceptación para determinar el resultado de la llamada.

SíntomaQué verificar
400 o 422Lee los detalles de campo del error. Verifica el formato del número, la elegibilidad y propiedad del número de llamada, los ID de secuencia y entrada, el objeto de datos explícito y los límites de solicitud.
401 o 403Verifica tu clave API o inicio de sesión OAuth, ambos permisos de escritura requeridos y el acceso al espacio de trabajo.
404Verifica que la secuencia pertenece al espacio de trabajo seleccionado y que la creación de llamadas está disponible en el servicio regional.
409Verifica si hay un reintento con cuerpo modificado o una secuencia de producción activa no disponible. Publica o reanuda según sea necesario antes de iniciar una nueva llamada.
429Respeta la guía de reintentos de la respuesta. Si proporcionaste una clave, reutilízala para el mismo intento de llamada.
Aceptada, luego fallóInspecciona la ejecución y cualquier registro de tramo en busca de destino, límites, saldo o errores de ejecución antes de decidir realizar otra llamada.

Próximos pasos

Continúa con la documentación, guías y ejemplos de este tema.