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

# Construire et publier votre premier flux IVR

> Créez un flux IVR dans la DSL Orbit ou dans le builder visuel, validez-le avant publication, simulez un appelant scripté, attachez-le à un DID, transférez à un humain quand nécessaire, et revenez en arrière avec l'historique des versions.

## Note de langue

Cette version française est une traduction abrégée : les sections « 3. Validate before you publish », « 7. The visual builder — the same graph, without the JSON » et « 8. Version and roll back » n'existent qu'en anglais : [/en/guides/build-ivr-flow](https://docs.orbit.devotel.io/en/guides/build-ivr-flow). Les blocs de code, chemins d'endpoints, noms de champs API et codes d'erreur restent en anglais.

# Construire et publier votre premier flux IVR

Un flux IVR est un graphe `{ nodes, edges }` que vous soumettez à un unique jeu d'endpoints. À la création comme à chaque modification, le validateur de graphe s'exécute avant la persistance ; la publication copie le brouillon dans le snapshot live ; et un simulateur vous fait piloter un appelant scripté dans le graphe avant qu'un DID ne sonne.

Nous construisons un petit flux de type compagnie aérienne : accueillir l'appelant, router les intents réservation ou remboursement vers une file ACD, et retomber sur la messagerie vocale si rien ne correspond.

## 1. Les primitives IVR

Les définitions de flux sont exécutées par le runtime voice contre le pipeline de verbes Jambonz. Le validateur de graphe — qui tourne à chaque create et update — vérifie exactement un nœud d'entrée (type `ivrStart`), au moins un nœud terminal (hangup, transfer, voicemail, ringGroup, dialByName, offerCallback, offerSmsCallback, scheduleCallback), que chaque edge référence des ids de nœuds existants, que tout nœud est atteignable depuis l'entrée et qu'aucun nœud atteignable n'est piégé dans un cycle sans route vers un terminal. Les briques reflètent la DSL voice programmable — voir la [Programmable Voice DSL reference](https://docs.orbit.devotel.io/reference/programmable-voice-dsl.md).

Les intents vocaux complètent les menus DTMF : les types de nœud `speechInput` et `dialByName` comparent un énoncé libre aux `speechIntents` par nœud. La [page concept IVR intents](https://docs.orbit.devotel.io/voice/ivr-intents.md) explique ces buckets.

> [!WARNING]
>
> La terminaison sortante est exclusivement Devotel. Un nœud `transfer` dont la destination est une SIP URI brute est rejeté par le validateur avec `transfer_external_sip` — utilisez un numéro E.164 ou un poste interne.

## 2. Construire le flux

Envoyez la définition à `POST /api/v1/voice/ivr-flows`. Le corps accepte `name`, le graphe `definition` et un drapeau `active` optionnel. Le validateur tourne avant la persistance : un graphe malformé rend `422 IVR_FLOW_GRAPH_INVALID` et rien n'est stocké.

```bash cURL theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/voice/ivr-flows" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Airline inbound router",
    "definition": {
      "nodes": [
        { "id": "start", "type": "ivrStart" },
        { "id": "welcome", "type": "playAudio", "data": { "ttsText": "Welcome to Horizon Airlines." } },
        {
          "id": "menu",
          "type": "menu",
          "data": {
            "menuOptions": [
              { "key": "1", "label": "Bookings" },
              { "key": "2", "label": "Support agent" }
            ]
          }
        },
        { "id": "bookings", "type": "queue", "data": { "label": "Bookings queue" } },
        { "id": "support", "type": "queue", "data": { "label": "Support queue" } },
        { "id": "fallback", "type": "voicemail", "data": { "label": "Voicemail fallback" } },
        { "id": "end", "type": "hangup" }
      ],
      "edges": [
        { "source": "start", "target": "welcome" },
        { "source": "welcome", "target": "menu" },
        { "source": "menu", "target": "bookings", "sourceHandle": "1" },
        { "source": "menu", "target": "support", "sourceHandle": "2" },
        { "source": "menu", "target": "fallback", "sourceHandle": "default" },
        { "source": "fallback", "target": "end" }
      ]
    }
  }'
```

La réponse porte l'`id` du nouveau flux (un identifiant `ivr_*`) — gardez-le ; chaque étape suivante l'utilise.

Les nœuds menu branchent une edge par touche DTMF présente dans `menuOptions` ; le validateur rejette les clés vides, dupliquées ou non-DTMF avec `menu_empty_key`, `menu_duplicate_key` ou `menu_invalid_key`.

## 4. Tester avec le simulateur

Pilotez un appelant scripté dans le graphe avant de l'attacher à un DID. `POST /api/v1/voice/ivr-flows/:id/simulate` consomme des `turns` (chacun avec `digits`, `speech` et/ou `intent`) et rend, pour chaque étape, l'id du nœud visité, le handle pris, les catégories de verbes émises et le `termination_reason`.

```bash cURL theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/voice/ivr-flows/ivr_01h.../simulate" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "turns": [{ "digits": "1" }],
    "max_steps": 50
  }'
```

**200 OK** — attendez `reached_nodes: ["start","welcome","menu","bookings"]`, `emitted_verbs` incluant `gather` au menu et `enqueue` à la file, et `termination_reason: "queue_answered"`. Une simulation rouge attrape les régressions de routage avant de brûler une minute live.

Options utiles : `source: "published"` parcourt le snapshot live, `source: "draft"` (défaut) le brouillon non sauvegardé.

## 5. Attacher le flux à un DID

La configuration de routage entrant de chaque DID porte la référence du flux. Posez `type: "ivr"` avec `config.flowId` :

```bash cURL theme={null}
curl -X PUT "https://api.orbit.devotel.io/api/v1/numbers/+14155550123/routing" \
  -H "X-API-Key: dv_live_sk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "type": "ivr", "config": { "flowId": "ivr_01h..." } }'
```

La passerelle voice résout le flux à chaque appel entrant — l'attachement est immédiat. Publiez avant d'attacher, et le premier appelant touchera le snapshot live.

## 6. Transférer à un agent

Routez la branche `support` vers une file ACD via un nœud `queue` pour qu'un membre de l'équipe prenne l'appel depuis le dashboard, ou dirigez tout le flux vers un [agent IA](https://docs.orbit.devotel.io/voice/ai-agent-handback.md) dont l'endpoint de handback conserve la conversation et rend la main à l'IA une fois l'exception résolue par un humain.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.