---
title: "Membuat panggilan suara"
description: "Mulai panggilan keluar dengan sequence Voice yang sudah dipublikasikan atau definisi inline melalui API, periksa hasilnya, dan pelajari pratinjau CLI dan MCP."
---

# Membuat panggilan suara

> **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.

Gunakan [`POST /v1/voice/calls`](/docs/api/reference/create-voice-call) untuk menelepon nomor telepon dan memulai sequence yang dipublikasikan, atau definisi sequence yang dikirim bersama permintaan, saat penerima mengangkat. Permintaan ini melakukan panggilan nyata; biaya panggilan normal berlaku.

**Pratinjau CLI dan MCP:** Antarmuka ini memerlukan klien yang kompatibel. Pastikan server MCP Anda menyediakan `voice_calls_create`, atau jalankan `bird voice --help` untuk menampilkan perintah di CLI Anda. Periksa rilis yang lebih baru dengan `bird update --check` dan lihat [Instalasi CLI](/docs/cli). Jika tool atau perintah tidak tersedia, gunakan API HTTP atau SDK.

Dalam pratinjau, CLI dan MCP menyiapkan panggilan yang sama agar seseorang dapat meninjau dan menjalankannya di browser. Agen menerima hasil penerimaan yang tercatat setelah orang tersebut menjalankan permintaan.

## Sebelum Anda mulai

Siapkan sumber daya berikut di workspace yang sama:

- Sequence yang akan dijalankan: [sequence yang aktif dan tidak diarsipkan dengan publikasi aktif](/docs/guides/voice/sequences/publishing) yang dibuat di dashboard, atau definisi lengkap yang dikirim bersama permintaan.
- [Kunci API](/docs/api/authentication) untuk permintaan HTTP, atau login OAuth untuk CLI dan MCP, dengan izin `voice_management:write` dan `voice:write`.
- Nomor pemanggil yang boleh ditampilkan workspace, seperti [caller ID](/docs/guides/voice/caller-ids) milik sendiri atau terverifikasi, dan [negara tujuan](/docs/guides/voice/destinations) yang diaktifkan. Gunakan nomor di negara penerima: beberapa jaringan seluler menolak panggilan yang menampilkan caller ID asing.
- Penerima yang Anda kontrol untuk panggilan pertama.

Objek `sequence` menerima tepat satu dari `sequence.id` atau `sequence.definition`. Keduanya juga memerlukan `entry_node_id`, langkah **Start call** tempat panggilan dimulai, dan `trigger_data`, objek yang sesuai dengan skema data entri tersebut. Gunakan `{}` jika entri menerima data kosong. [Referensi Create Call](/docs/api/reference/create-voice-call) mendokumentasikan batas permintaan dan waktu tunggu dering opsional.

## Memanggil sequence yang dibuat di dashboard

Gunakan `sequence.id` untuk menjalankan sequence yang Anda [buat](/docs/guides/voice/sequences/editor) dan [publikasikan](/docs/guides/voice/sequences/publishing) di dashboard. Create Call selalu menjalankan publikasi aktifnya.

1. Buka sequence di [**Sequences**](https://bird.com/dashboard/w/voice/sequences).
2. Di bagian **How to run this sequence**, pilih **More details** di samping **Create a call**.
3. Jika sequence memiliki beberapa entry, pilih **Call trigger** yang akan dimulai.
4. Salin permintaan tersebut. Permintaan berisi sequence ID dan entry ID.

Simpan body permintaan sebagai `call.json`, ganti nomor contoh dengan nomor Anda sendiri:

```json
{
  "from": "+12025550100",
  "to": "+12025550101",
  "sequence": {
    "id": "YOUR_SEQUENCE_ID",
    "entry_node_id": "YOUR_ENTRY_NODE_ID",
    "trigger_data": {}
  }
}
```

Isi `trigger_data` dengan field yang dideklarasikan entry, termasuk objek dan array bersarang. Create Call tidak menerima versi historis, draf, atau mode pengujian. Untuk menguji draf tersimpan, gunakan kontrol [Place a call](/docs/guides/voice/sequences/testing) di dashboard.

## Menjalankan sequence inline

Gunakan `sequence.definition` untuk mengirim sequence lengkap bersama panggilan. Bird menjalankannya sekali dan tidak menyimpannya, sehingga panggilan tidak memiliki sequence ID. Definisi inline cocok untuk alur yang dihasilkan aplikasi Anda per panggilan.

Definisi inline harus lolos pemeriksaan yang sama seperti saat memublikasikan sequence. Eksekusinya dapat menjalankan maksimal 16 perintah, termasuk prompt gather; panggilan yang membutuhkan perintah ke-17 berakhir dengan trace error `call_limit`. [Referensi node](/docs/guides/voice/sequences/node-reference) mencantumkan setiap langkah yang dapat Anda gunakan, beserta field dan outcome-nya. Untuk memulai dari flow yang sudah berjalan, buat dan publikasikan di dashboard, buka sequence tersebut, lalu pilih **Copy JSON** pada **Definition JSON** di bawah **Published version**.

`call.json` ini meminta penerima menekan 1 untuk jam buka atau 2 untuk petunjuk arah. Diam dan tombol lainnya mengakhiri run dengan alasan keluar masing-masing:

```json
{
  "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": {} }
        }
      ]
    }
  }
}
```

`connections` setiap node memetakan hasil ke node berikutnya. `matches` menu menamai pilihan-pilihannya, dan `connections` menggunakan nama yang sama bersama hasil bawaan `timeout` dan `fallback`.

### Personalisasi sequence inline

Deklarasikan field yang Anda kirim di `data_schema` entry, lalu baca sebagai `trigger.data.<field>` dalam nilai `$expr`. Panggilan ini menyapa penerima berdasarkan nama dan mengonfirmasi atau menandai janji temu mereka:

```json
{
  "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` dan `reason` setiap exit memisahkan konfirmasi, permintaan bantuan, dan tanpa respons. Objek `trigger_data` yang tidak cocok dengan `data_schema` gagal validasi, dengan lokasinya di bawah `/sequence/trigger_data`, dan panggilan tidak dilakukan.

## Kirim permintaan

Pilih satu metode permintaan di bawah untuk `call.json` yang Anda simpan.

Pilih kunci idempotensi yang baru dan unik sekali untuk panggilan yang dimaksud ini. Simpan kunci tersebut dan input asli untuk percobaan ulang atau pemulihan konfirmasi. Pilih kunci lain jika Anda bermaksud melakukan panggilan baru yang terpisah, setelah menyelesaikan hasil yang tidak diketahui dari panggilan asli.

Untuk contoh shell, atur `IDEMPOTENCY_KEY` ke nilai pilihan Anda sebelum mengirim. Contoh akan berhenti jika nilainya tidak diatur atau kosong; contoh tidak menghasilkan kunci lain jika diulang.

Untuk HTTP, atur `BIRD_API_KEY` ke kunci Anda dan `BIRD_API_URL` ke [URL basis regional](/docs/api/regions)-nya, misalnya `https://eu1.platform.bird.com` untuk kunci `eu1`, lalu kirim permintaan:

```bash
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
```

Untuk pratinjau [CLI](/docs/cli), masuk dengan kedua izin tulis dan siapkan panggilan menggunakan file yang sama:

```bash
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}"
```

Perintah mencetak tautan tinjauan browser dan menunggu penyelesaian. Buka tautan tersebut, periksa pemanggil, penerima, sequence, dan data entry, lalu jalankan permintaan sendiri. Menyiapkan permintaan tidak melakukan panggilan. Tambahkan `--dry-run` untuk memeriksa permintaan CLI tanpa membuat konfirmasi. Jika konfirmasi kedaluwarsa, dibatalkan, atau berakhir tanpa hasil tercatat, perintah keluar dengan `5`; ikuti [panduan percobaan ulang](#menangani-kesalahan-dan-percobaan-ulang) sebelum membuat permintaan lain.

Untuk pratinjau [MCP](/docs/ai/mcp-server), panggil `voice_calls_create` dengan field dari `call.json` dan `idempotency_key` yang wajib. Ganti `<unique-key-for-this-request-reuse-for-retries>` dengan kunci pilihan Anda:

```json
{
  "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>"
}
```

Ikuti tautan tinjauan browser yang dikembalikan untuk menjalankan permintaan. Pada endpoint MCP dinamis, pilih `voice_calls_create` melalui `execute`. Persetujuan OAuth memberikan izin workspace; tinjauan browser menjalankan panggilan spesifik ini.

Respons `202 Accepted` mengonfirmasi penerimaan. Sequence dimulai setelah penerima menjawab. Mempublikasikan versi yang lebih baru setelah penerimaan tidak mengubah definisi atau data entry yang dipilih untuk panggilan ini.

## Baca hasil penerimaan

Simpan `id`, `initial_leg_id`, dan `sequence.run_id` dari respons untuk korelasi. `id` tingkat atas mengidentifikasi panggilan di seluruh leg-nya; `initial_leg_id` mengidentifikasi leg pertamanya.

Respons adalah snapshot penerimaan yang tidak dapat diubah. `started_at` dan `ended_at`-nya bernilai `null`, boolean observasi bernilai `false`, dan `parties` kosong. Field-field ini menjelaskan penerimaan, sehingga tidak menjadi laporan status langsung saat Anda memutar ulang permintaan.

Buka [**Runs**](/docs/guides/voice/sequences/runs) pada sequence untuk memeriksa progres. Panggilan inline tidak termasuk dalam sequence mana pun, jadi ikuti leg-nya; jika gagal sebelum leg-nya terdaftar, belum ada cara untuk memeriksanya. Setelah catatan leg tersedia, gunakan [`GET /v1/voice/legs/{leg_id}`](/docs/api/reference/get-voice-leg) dengan `initial_leg_id`, atau periksa [call log](/docs/guides/voice/call-log). Membaca leg memerlukan izin `voice:read`, yang sudah tercakup dalam `voice:write`.

Leg dengan `status` `rejected` ditolak sebelum terhubung, sehingga sequence-nya tidak berjalan. Tanpa alasan penolakan, ujung lain menolak panggilan tersebut; lihat [Rejected calls](/docs/guides/voice/call-log#rejected-calls).

Dengan CLI, `bird voice calls get YOUR_CALL_ID` menampilkan panggilan dan pihak-pihaknya. `bird voice legs trace YOUR_LEG_ID` menampilkan langkah mana yang dijalankan, digit yang dikumpulkan kecuali gather bersifat privat, serta status dan alasan exit. Trace tersedia tak lama setelah panggilan berakhir; sebelum itu perintah mengembalikan error, jadi coba lagi. Sequence dari leg yang ditolak tidak pernah berjalan, sehingga mungkin tidak memiliki trace.

Penerimaan tidak menjamin pemanggilan, jawaban, atau catatan panggilan yang dapat dibaca. Panggilan yang gagal sebelum registrasi mungkin muncul di riwayat run tanpa catatan leg. Panggilan yang dijawab juga tidak membuktikan bahwa sequence menyelesaikan tugas bisnis yang dimaksud.

## Menangani kesalahan dan percobaan ulang

Untuk permintaan HTTP langsung, idempotensi bersifat opsional. Tanpa kunci, setiap permintaan menerima percobaan panggilan baru. SDK menghasilkan kunci untuk percobaan ulang otomatis. Untuk melindungi percobaan ulang lintas panggilan terpisah atau permintaan HTTP langsung, berikan kunci pada percobaan pertama dan gunakan kembali dengan byte permintaan asli yang sama persis. Lihat [panduan idempotensi](/docs/guides/idempotency).

Pengulangan identik dalam tiga jam mengembalikan penerimaan asli dan `Idempotency-Replay: true`. Input yang diubah dengan kunci tersebut mengembalikan `409`. Otorisasi dan izin nomor pemanggil diperiksa kembali saat pengulangan. Setelah jendela pengulangan, kunci dapat menerima panggilan baru, jadi rekonsiliasi hasil asli sebelum mengirim ulang.

Untuk CLI dan MCP, berikan kunci idempotensi pada percobaan pertama. Mengulangi permintaan dan kunci yang sama dengan grant OAuth yang sama mengembalikan konfirmasi yang ada selama catatannya masih disimpan. Simpan input asli dan ID konfirmasi. Mengubah kunci dapat menyiapkan panggilan berbayar lain.

Jika perintah CLI terputus, lanjutkan dengan input asli, kunci, dan ID konfirmasi yang dikembalikan:

```bash
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
```

Untuk MCP, ulangi argumen tool asli, termasuk `idempotency_key` yang sama, bersama dengan state permintaan yang dikembalikan. State mengidentifikasi konfirmasi dan tidak menggantikan argumen tersebut. Alternatifnya, ulangi tool dan argumen yang sama dengan ID yang dikembalikan di metadata permintaan `bird/confirmation-id`. Dengan MCP dinamis, ulangi permintaan `execute` yang sama dan letakkan metadata tersebut di dalamnya. Melanjutkan membaca konfirmasi asli dan mengembalikan hasil tercatatnya setelah selesai.

Konfirmasi Create Call kedaluwarsa setelah 90 menit. Konfirmasi `pending` atau `expired` tanpa hasil tidak membuktikan panggilan tidak pernah dijalankan. Periksa run sequence asli dan catatan call-leg sebelum memutuskan untuk melakukan panggilan lain; jangan membuat kunci baru untuk menyelesaikan hasil yang tidak diketahui. Konfirmasi selesai dengan hasil `202` membuktikan penerimaan, jadi lanjutkan dengan [pemeriksaan penerimaan](#baca-hasil-penerimaan) untuk mengetahui hasil panggilan.

| Gejala               | Yang perlu diperiksa                                                                                                                                                                      |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400` atau `422`     | Baca detail field kesalahan. Periksa format nomor, kelayakan dan kepemilikan nomor pemanggil, sequence dan entry ID, objek data eksplisit, dan batas permintaan.                          |
| `401` atau `403`     | Periksa kunci API atau login OAuth Anda, kedua izin tulis yang diperlukan, dan akses workspace.                                                                                           |
| `404`                | Periksa apakah sequence milik workspace yang dipilih dan pembuatan panggilan tersedia di layanan regional.                                                                                |
| `409`                | Periksa apakah ada percobaan ulang dengan body yang diubah atau sequence produksi aktif yang tidak tersedia. Publikasikan atau lanjutkan sesuai kebutuhan sebelum memulai panggilan baru. |
| `429`                | Patuhi panduan percobaan ulang dari respons. Jika Anda memberikan kunci, gunakan kembali untuk percobaan panggilan yang sama.                                                             |
| Diterima, lalu gagal | Periksa run dan catatan leg untuk tujuan, batas, saldo, atau kegagalan runtime sebelum memutuskan untuk melakukan panggilan lain.                                                         |

## Langkah selanjutnya

- [Referensi API Create Call](/docs/api/reference/create-voice-call).
- [Mendefinisikan data entry sequence](/docs/guides/voice/sequences/data).
- [Memeriksa run sequence](/docs/guides/voice/sequences/runs).
- [Menerima event panggilan](/docs/guides/voice/events).

## Related resources

- [Voice sequences](/docs/guides/voice/sequence-builder) (docs)
