Sign inGet Started

Créer un appel vocal

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.

Utilisez POST /v1/voice/calls pour appeler un numéro de téléphone et démarrer une séquence publiée, ou une définition de séquence envoyée avec la requête, lorsque le destinataire décroche. La requête lance un véritable appel ; les frais d'appel habituels s'appliquent.

Préversion CLI et MCP : Ces interfaces nécessitent un client compatible. Vérifiez que votre serveur MCP expose voice_calls_create, ou exécutez bird voice --help pour afficher les commandes de votre CLI. Recherchez les versions plus récentes avec bird update --check et consultez Installation de CLI. Si l'outil ou la commande n'est pas disponible, utilisez l'API HTTP ou les SDK.

Dans la préversion, CLI et MCP préparent le même appel pour qu'une personne le vérifie et l'exécute dans le navigateur. L'agent reçoit le résultat d'acceptation enregistré après que la personne a exécuté la requête.

Avant de commencer

Préparez ces ressources dans le même espace de travail :

  • Une séquence à exécuter : une séquence activée et non archivée avec une publication active créée dans le tableau de bord, ou une définition complète envoyée avec la requête.
  • Une clé API pour les requêtes HTTP, ou une connexion OAuth pour CLI et MCP, avec les permissions voice_management:write et voice:write.
  • Un numéro d'appel que l'espace de travail peut présenter, tel qu'un identifiant d'appelant détenu ou vérifié, et un pays de destination activé. Préférez un numéro dans le pays du destinataire : certains réseaux mobiles refusent un appel qui présente un identifiant d'appelant étranger.
  • Un destinataire que vous contrôlez pour le premier appel.

L'objet sequence accepte exactement l'un des deux champs sequence.id ou sequence.definition. Les deux nécessitent aussi entry_node_id, l'étape Start call à laquelle l'appel démarre, et trigger_data, un objet conforme au schéma de données de cette entrée. Utilisez {} lorsque l'entrée accepte des données vides. La référence Create Call documente les limites de requête et le délai de sonnerie optionnel.

Appeler une séquence créée dans le tableau de bord

Utilisez sequence.id pour exécuter une séquence que vous avez créée et publiée dans le tableau de bord. Create Call exécute toujours sa publication active.

  1. Ouvrez la séquence dans Sequences.
  2. Sous How to run this sequence, sélectionnez More details à côté de Create a call.
  3. Si la séquence comporte plusieurs entrées, choisissez le Call trigger de départ.
  4. Copiez la requête. Elle contient l'identifiant de séquence et l'identifiant d'entrée.

Enregistrez le corps de la requête sous call.json, en remplaçant les numéros d'exemple par les vôtres :

Exemple de code
{
  "from": "+12025550100",
  "to": "+12025550101",
  "sequence": {
    "id": "YOUR_SEQUENCE_ID",
    "entry_node_id": "YOUR_ENTRY_NODE_ID",
    "trigger_data": {}
  }
}

Remplissez trigger_data avec les champs déclarés par l'entrée, y compris les objets et tableaux imbriqués. Create Call n'accepte ni les versions historiques, ni les brouillons, ni le mode test. Pour tester un brouillon enregistré, utilisez les commandes Passer un appel du tableau de bord.

Exécuter une séquence en ligne

Utilisez sequence.definition pour envoyer une séquence complète avec l'appel. Bird l'exécute une seule fois sans l'enregistrer, de sorte que l'appel n'a pas d'identifiant de séquence. Une définition en ligne convient aux flux que votre application génère à chaque appel.

Une définition en ligne doit passer les mêmes contrôles que la publication d'une séquence. Son exécution peut traiter au maximum 16 commandes, y compris les invites de collecte ; un appel qui nécessite une 17e commande se termine avec l'erreur de trace call_limit. La référence des nœuds liste chaque étape utilisable, avec ses champs et résultats. Pour partir d'un flux fonctionnel, construisez-le et publiez-le dans le tableau de bord, ouvrez la séquence, puis sélectionnez Copy JSON sur Definition JSON sous Published version.

Cette call.json demande au destinataire d'appuyer sur 1 pour les horaires d'ouverture ou sur 2 pour l'itinéraire. Le silence et toute autre touche mettent fin à l'exécution avec leurs propres raisons de sortie :

Exemple de code
{
  "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": {} }
        }
      ]
    }
  }
}

Le champ connections de chaque nœud associe un résultat au nœud suivant. Le champ matches du menu nomme ses choix, et connections utilise les mêmes noms aux côtés des résultats intégrés timeout et fallback.

Personnaliser une séquence en ligne

Déclarez les champs que vous envoyez dans le data_schema de l'entrée, puis lisez-les sous forme de trigger.data.<field> dans une valeur $expr. Cet appel salue le destinataire par son nom et confirme ou signale son rendez-vous :

Exemple de code
{
  "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" } }
          }
        }
      ]
    }
  }
}

Les champs status et reason de chaque sortie distinguent une confirmation, une demande d'aide et l'absence de réponse. Un objet trigger_data qui ne correspond pas à data_schema échoue à la validation, avec son emplacement sous /sequence/trigger_data, et aucun appel n'est passé.

Envoyer la requête

Choisissez ci-dessous une méthode de requête pour le call.json que vous avez enregistré.

Choisissez une clé d'idempotence unique et nouvelle une seule fois pour cet appel prévu. Conservez cette clé et l'entrée d'origine pour les nouvelles tentatives ou la récupération de confirmation. Choisissez une autre clé lorsque vous souhaitez passer un nouvel appel distinct, après avoir résolu tout résultat inconnu pour l'appel d'origine.

Pour les exemples shell, définissez IDEMPOTENCY_KEY sur la valeur choisie avant l'envoi. Les exemples s'arrêtent si la variable est non définie ou vide ; ils ne génèrent pas une autre clé lorsqu'ils sont répétés.

Pour HTTP, définissez BIRD_API_KEY sur votre clé et BIRD_API_URL sur son URL de base régionale, par exemple https://eu1.platform.bird.com pour une clé eu1, puis envoyez la requête :

Exemple de code
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

Pour la préversion CLI, connectez-vous avec les deux permissions d'écriture et préparez l'appel en utilisant le même fichier :

Exemple de code
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}"

La commande affiche un lien de vérification dans le navigateur et attend la fin de l'opération. Ouvrez le lien, vérifiez l'appelant, le destinataire, la séquence et les données d'entrée, puis exécutez la requête vous-même. Préparer la requête ne passe pas l'appel. Ajoutez --dry-run pour inspecter la requête CLI sans créer de confirmation. Si la confirmation expire, est annulée ou se termine sans résultat enregistré, la commande se termine avec 5 ; suivez le guide de nouvelle tentative avant de soumettre une autre requête.

Pour la préversion MCP, appelez voice_calls_create avec les champs de call.json et un idempotency_key obligatoire. Remplacez <unique-key-for-this-request-reuse-for-retries> par la clé choisie :

Exemple de code
{
  "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>"
}

Suivez le lien de vérification dans le navigateur renvoyé pour exécuter la requête. Sur l'endpoint dynamique MCP, sélectionnez voice_calls_create via execute. Le consentement OAuth accorde les permissions de l'espace de travail ; la vérification dans le navigateur exécute cet appel précis.

Une réponse 202 Accepted confirme l'admission. La séquence commence après que le destinataire a répondu. Publier une version plus récente après l'acceptation ne modifie ni la définition sélectionnée ni les données d'entrée de cet appel.

Lire le résultat d'acceptation

Conservez les valeurs id, initial_leg_id et sequence.run_id de la réponse pour la corrélation. Le champ id de niveau supérieur identifie l'appel à travers ses segments ; initial_leg_id identifie son premier segment.

La réponse est un instantané d'acceptation immuable. Ses champs started_at et ended_at sont null, les booléens d'observation sont false et parties est vide. Ces champs décrivent l'acceptation et ne deviennent donc pas un rapport d'état en temps réel lorsque vous rejouez la requête.

Ouvrez les Runs de la séquence pour suivre la progression. Un appel en ligne n'appartient à aucune séquence ; suivez plutôt son leg. S'il échoue avant l'enregistrement de son leg, il n'existe pas encore de moyen de l'inspecter. Une fois qu'un enregistrement de leg existe, utilisez GET /v1/voice/legs/{leg_id} avec initial_leg_id, ou consultez le journal d'appels. La lecture des legs nécessite la permission voice:read, incluse dans voice:write.

Un leg avec status rejected a été refusé avant la connexion, donc sa séquence ne s'est pas exécutée. Sans motif de rejet, le correspondant distant a décliné l'appel ; voir Appels rejetés.

Avec le CLI, bird voice calls get YOUR_CALL_ID affiche l'appel et ses participants. bird voice legs trace YOUR_LEG_ID affiche les étapes exécutées, les chiffres collectés sauf si le gather est privé, ainsi que le statut et la raison de sortie. La trace est disponible peu après la fin de l'appel ; jusque-là, la commande renvoie une erreur, réessayez donc. La séquence d'un leg refusé n'a jamais été exécutée, il peut donc ne pas y avoir de trace.

L'acceptation ne garantit ni la numérotation, ni une réponse, ni un enregistrement d'appel lisible. Un appel qui échoue avant l'enregistrement peut apparaître dans l'historique des exécutions sans enregistrement de segment. Un appel décroché n'établit pas non plus que la séquence a accompli sa tâche métier prévue.

Gérer les erreurs et les nouvelles tentatives

Pour les requêtes HTTP directes, l'idempotence est facultative. Sans clé, chaque requête accepte une nouvelle tentative d'appel. Les SDK génèrent une clé pour les nouvelles tentatives automatiques. Pour protéger les nouvelles tentatives entre des appels distincts ou des requêtes HTTP directes, fournissez une clé dès la première tentative et réutilisez-la avec les octets exacts de la requête d'origine. Consultez le guide d'idempotence.

Un rejeu identique dans les trois heures renvoie l'acceptation d'origine et Idempotency-Replay: true. Une entrée modifiée avec cette clé renvoie 409. L'autorisation et la permission du numéro d'appel sont vérifiées à nouveau lors du rejeu. Après la fenêtre de rejeu, la clé peut admettre un nouvel appel : réconciliez le résultat d'origine avant de soumettre à nouveau.

Pour CLI et MCP, fournissez la clé d'idempotence dès la première tentative. Répéter la même requête et la même clé avec le même octroi OAuth renvoie la confirmation existante tant que son enregistrement est conservé. Conservez l'entrée d'origine et l'identifiant de confirmation. Changer la clé peut préparer un autre appel facturable.

Si la commande CLI est interrompue, reprenez avec l'entrée d'origine, la clé et l'identifiant de confirmation renvoyé :

Exemple de code
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

Pour MCP, répétez les arguments d'outil d'origine, y compris le même idempotency_key, avec l'état de requête renvoyé. L'état identifie la confirmation et ne remplace pas ces arguments. Vous pouvez aussi répéter le même outil et les mêmes arguments avec l'identifiant renvoyé dans les métadonnées de requête bird/confirmation-id. Avec le MCP dynamique, répétez la même requête execute et ajoutez-y ces métadonnées. La reprise lit la confirmation d'origine et renvoie son résultat enregistré une fois terminée.

Une confirmation Create Call expire après 90 minutes. Une confirmation pending ou expired sans résultat ne prouve pas que l'appel n'a jamais été passé. Inspectez l'exécution de la séquence d'origine et tout enregistrement de segment d'appel avant de décider de passer un autre appel ; ne créez pas une nouvelle clé pour résoudre un résultat inconnu. Une confirmation terminée avec un résultat 202 prouve l'acceptation : poursuivez avec les vérifications d'acceptation pour établir le résultat de l'appel.

SymptômeQue vérifier
400 ou 422Lisez les détails des champs de l'erreur. Vérifiez le format du numéro, l'éligibilité et la propriété du numéro d'appel, les identifiants de séquence et d'entrée, l'objet de données explicite et les limites de requête.
401 ou 403Vérifiez votre clé API ou votre connexion OAuth, les deux permissions d'écriture requises et l'accès à l'espace de travail.
404Vérifiez que la séquence appartient à l'espace de travail sélectionné et que la création d'appels est disponible sur le service régional.
409Vérifiez s'il s'agit d'une nouvelle tentative avec un corps modifié ou d'une séquence de production active indisponible. Publiez ou reprenez selon les besoins avant de lancer un nouvel appel.
429Respectez les indications de nouvelle tentative de la réponse. Si vous avez fourni une clé, réutilisez-la pour la même tentative d'appel.
Accepté, puis échouéInspectez l'exécution et tout enregistrement de segment pour la destination, les limites, le solde ou les erreurs d'exécution avant de décider de passer un autre appel.

Étapes suivantes

Poursuivez avec la documentation, les guides et les exemples sur ce sujet.