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

# قوائم الرد الصوتي (IVR)

> أنشئ قائمة صوتية بالضغط على الأرقام يسمعها المتّصلون عند الاتّصال برقمك.

تُرحّب **قائمة الرد الصوتي (IVR)** بالمتّصل، وتقرأ عليه بعض الخيارات، ثم توجّهه حسب
الزرّ الذي يضغطه — *"اضغط 1 للمبيعات، اضغط 2 للدعم."* تُنشئ القائمة مرّة واحدة عبر هذه
الواجهة (أو [لوحة التحكّم](https://wave.sa))، وتربطها بأحد أرقام Wave لديك، فتُقدّمها
Wave مباشرةً لكلّ متّصل — دون إعادة نشر.

خلف الكواليس تُترجَم القائمة إلى أمر [WaveML](/ar/voice/waveml) وهو `<Gather>` يُشغّل
التحية ويجمع ضغطة زرّ واحدة، ثم يُنفّذ الفرع الخاصّ بذلك الرقم. هذه الواجهة هي طبقة
**التأليف** فوق WaveML — تصف القائمة بصيغة JSON وتحوّلها Wave إلى مسار مكالمة.

<Note>
  هذه هي القائمة **أحادية المستوى** — تحية واحدة ومجموعة خيارات واحدة، ينهي كلٌّ منها
  المكالمة أو يحوّلها. القوائم الفرعية المتداخلة وأداة البناء المرئية ميزات منفصلة
  لاحقة. للتفريعات الكاملة اليوم، أعِد [WaveML](/ar/voice/waveml) من نقطة النهاية
  الخاصّة بك بدلاً من ذلك.
</Note>

## المصادقة والطبقات

تتطلّب جميع نقاط `/v1/callflows` مفتاح واجهة بنطاق `callflows:read` أو
`callflows:write`، **أو** جلسة لوحة تحكّم. يمكنك **التأليف والاختبار** بمفتاح
**sandbox** (`sk_sandbox_`)، أمّا تقديم قائمة إلى **مكالمة واردة حقيقية** فيتطلّب مفتاح
**production** (`sk_live_`) ومؤسسة بطبقة production ورقمًا مربوطًا (راجع **ربط رقم** أدناه).

## تعريف القائمة

القائمة عبارة عن `definition` بصيغة JSON: تحية، وفروع لوحة المفاتيح، واحتياطيّ اختياريّ
عند عدم ضغط المتّصل أيّ زرّ.

```json theme={null}
{
  "prompt": { "say": { "text": "To authenticate press 1, to decline press 2", "language": "en" } },
  "gather": { "num_digits": 1, "timeout_seconds": 8 },
  "branches": [
    { "digit": "1", "action": { "say": { "text": "You are authenticated. Goodbye." } }, "input": { "authenticated": true } },
    { "digit": "2", "action": { "say": { "text": "You chose not to authenticate. Goodbye." } }, "input": { "authenticated": false } }
  ],
  "no_input": { "action": { "say": { "text": "We didn't get your input. Goodbye." } } }
}
```

| الحقل                    | النوع    | إلزاميّ | ملاحظات                                                    |
| ------------------------ | -------- | ------- | ---------------------------------------------------------- |
| `prompt`                 | كائن     | **نعم** | التحية. واحد فقط من `say` أو `play` (أدناه).               |
| `gather.num_digits`      | عدد صحيح | لا      | عدد الأرقام المطلوب جمعها، `1`–`10`. الافتراضيّ `1`.       |
| `gather.timeout_seconds` | عدد صحيح | لا      | ثواني الانتظار لضغطة زرّ، `1`–`60`. الافتراضيّ `8`.        |
| `branches`               | مصفوفة   | **نعم** | 1–12 خيارًا. يجب أن يكون كلّ `digit` فريدًا.               |
| `no_input`               | كائن     | لا      | الإجراء عند عدم ضغط المتّصل أيّ زرّ قبل `timeout_seconds`. |

### التحية والإجراءات

**التحية** وكلّ **إجراء فرع** هو أحد هذه الأنواع. إجراء الفرع طرفيّ — ينهي المكالمة أو
يحوّلها.

| الإجراء   | الشكل                                             | ما يفعله                                                   |
| --------- | ------------------------------------------------- | ---------------------------------------------------------- |
| `say`     | `{ "text": "…", "language"?: "en" }`              | ينطق نصًّا (TTS). `text` ≤ 1000 محرف.                      |
| `play`    | `{ "audio_ref": "https://…" }`                    | يشغّل **مقطعًا صوتيًّا** مسجّلًا (أدناه). تحيةً أو إجراءً. |
| `dial`    | `{ "number": "0112345678" }`                      | يحوّل المتّصل إلى رقم **سعوديّ**.                          |
| `enqueue` | `{ "queue": "support", "strategy"?: "ring-all" }` | يُرسل المتّصل إلى [طابور](/ar/voice/queues).               |
| `hangup`  | `true`                                            | ينهي المكالمة.                                             |

<Note>
  أهداف `dial` مقيّدة بأرقام **سعوديّة (KSA)** — حماية من الاحتيال، لأنّ `<Dial>` يجسر
  المتّصل إلى مسار جديد.
</Note>

### مُدخل الفرع (حمولة webhook خاصّتك)

امنح الفرع كائن `input`، فتدمجه Wave في [webhook باسم `call.input`](/ar/webhooks)
حين يختار المتّصل ذلك الخيار — نقطة ربط تكاملك لمعرفة **ما اختاره المتّصل**.

* حتّى 20 حقلًا؛ القيم نصّ (≤512) أو عدد أو قيمة منطقيّة.
* المفتاحان `call_id` و`digits` **محجوزان** (تضبطهما Wave) ويُرفضان.

## إنشاء قائمة

`POST /v1/callflows` — أنشئ قائمة بالاسم. مرّر `"activate": true` لجعلها مباشرة فورًا.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.wave.sa/v1/callflows \
    -H "Authorization: Bearer sk_sandbox_xxxxxxxxxxxx" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "auth-ivr",
      "activate": true,
      "definition": {
        "prompt": { "say": { "text": "To authenticate press 1, to decline press 2" } },
        "branches": [
          { "digit": "1", "action": { "say": { "text": "You are authenticated. Goodbye." } }, "input": { "authenticated": true } },
          { "digit": "2", "action": { "say": { "text": "You chose not to authenticate. Goodbye." } }, "input": { "authenticated": false } }
        ]
      }
    }'
  ```

  ```javascript JavaScript theme={null}
  await fetch("https://api.wave.sa/v1/callflows", {
    method: "POST",
    headers: {
      Authorization: "Bearer sk_sandbox_xxxxxxxxxxxx",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      name: "auth-ivr",
      activate: true,
      definition: {
        prompt: { say: { text: "To authenticate press 1, to decline press 2" } },
        branches: [
          { digit: "1", action: { say: { text: "You are authenticated. Goodbye." } }, input: { authenticated: true } },
          { digit: "2", action: { say: { text: "You chose not to authenticate. Goodbye." } }, input: { authenticated: false } },
        ],
      },
    }),
  });
  ```
</CodeGroup>

| الحقل        | النوع  | إلزاميّ | ملاحظات                                                                  |
| ------------ | ------ | ------- | ------------------------------------------------------------------------ |
| `name`       | نصّ    | **نعم** | `A–Z a–z 0–9 _ -` والمسافات، ≤100 محرف. فريد لكلّ مؤسسة — مفتاح التوجيه. |
| `definition` | كائن   | **نعم** | **تعريف القائمة** (أعلاه).                                               |
| `activate`   | منطقيّ | لا      | `true` يجعل هذا الإصدار مباشرًا عند الإنشاء. الافتراضيّ `false`.         |

يُعيد `201 Created` القائمة، متضمّنةً سجلّ إصداراتها:

```json theme={null}
{
  "name": "auth-ivr",
  "version": 1,
  "is_active": true,
  "definition": { "kind": "menu", "gather": { "…": "…" }, "branches": { "…": "…" } },
  "created_at": "2026-08-28T10:00:00.000Z",
  "updated_at": "2026-08-28T10:00:00.000Z",
  "versions": [ { "version": 1, "is_active": true, "created_at": "2026-08-28T10:00:00.000Z" } ]
}
```

الاسم المكرّر يُعيد `409` — استخدم `PUT` لإضافة إصدار بدلاً من ذلك.

## سرد القوائم وجلبها

يسرد `GET /v1/callflows` صفًّا واحدًا لكلّ قائمة (إصدارها النشط أو الأحدث):

```json theme={null}
{
  "data": [
    { "name": "auth-ivr", "version": 2, "is_active": true, "updated_at": "2026-08-28T11:00:00.000Z" }
  ]
}
```

يُعيد `GET /v1/callflows/{name}` القائمة كاملةً — `definition` الإصدار النشط (أو
الأحدث) مع سجلّ `versions` الكامل. `404` إن لم تكن القائمة موجودة.

## الإصدارات والاسترجاع

القوائم **غير قابلة للتغيير وتُضاف فقط**. التعديل لا يغيّر إصدارًا في مكانه أبدًا — بل
يُضيف إصدارًا جديدًا.

* `PUT /v1/callflows/{name}` بتعريف `definition` جديد (و`activate` اختياريّ) يُضيف
  **الإصدار التالي**. `404` إن لم تكن القائمة موجودة.
* `POST /v1/callflows/{name}/activate` بـ `{ "version": N }` يجعل الإصدار `N` مباشرًا —
  **الاسترجاع هو ببساطة تفعيل إصدار أقدم.** `404` إن لم يكن ذلك الإصدار موجودًا.

<CodeGroup>
  ```bash cURL theme={null}
  # الاسترجاع إلى الإصدار 1
  curl -X POST https://api.wave.sa/v1/callflows/auth-ivr/activate \
    -H "Authorization: Bearer sk_sandbox_xxxxxxxxxxxx" \
    -H "Content-Type: application/json" \
    -d '{ "version": 1 }'
  ```

  ```javascript JavaScript theme={null}
  await fetch("https://api.wave.sa/v1/callflows/auth-ivr/activate", {
    method: "POST",
    headers: {
      Authorization: "Bearer sk_sandbox_xxxxxxxxxxxx",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ version: 1 }),
  });
  ```
</CodeGroup>

يُعيد كلاهما كائن القائمة بالإصدار المُفعَّل حديثًا.

## ربط رقم

`POST /v1/callflows/{name}/bind-number` يوجّه أحد أرقام Wave لديك إلى الإصدار **النشط**
للقائمة — عندها تُنفّذ المكالمات الواردة إلى ذلك الرقم القائمة.

```bash cURL theme={null}
curl -X POST https://api.wave.sa/v1/callflows/auth-ivr/bind-number \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "phone_number_id": "f933e0c3-45a9-4b25-b469-624745a3f8ef" }'
```

| الحقل             | النوع | إلزاميّ | ملاحظات                                                                  |
| ----------------- | ----- | ------- | ------------------------------------------------------------------------ |
| `phone_number_id` | uuid  | **نعم** | رقم تملكه مؤسستك. `404` إن لم يكن لك؛ `409` إن لم يكن للقائمة إصدار نشط. |

يُعيد `{ "bound": true }`. الأرقام تُوفّرها Wave — راجع [الأرقام الافتراضيّة](/ar/voice/virtual-numbers).

## إيقاف قائمة

`DELETE /v1/callflows/{name}` يوقف القائمة إيقافًا ناعمًا: تتوقّف عن خدمة المتّصلين ويُلغى
ربط أيّ رقم، لكن يُحفَظ سجلّ الإصدارات (يمكنك إعادة إنشائها لاحقًا). يُعيد
`{ "retired": true }`؛ و`404` إن لم تكن القائمة موجودة.

## webhook باسم `call.input`

حين يضغط المتّصل رقمًا، تُرسل Wave webhook باسم [`call.input`](/ar/webhooks). تحمل
`data` الأرقام المضغوطة `digits` **إضافةً إلى** كائن `input` لذلك الفرع — فيعرف نظامك
الخلفيّ بالضبط ما اختاره المتّصل:

```json theme={null}
{
  "event": "call.input",
  "data": { "call_id": "…", "digits": "1", "authenticated": true }
}
```

سجّل نقطة نهاية وتحقّق من التوقيع كما هو موضّح في [Webhooks](/ar/webhooks).

## المقاطع الصوتيّة

تُشغّل تحية أو إجراء `play` ملفًّا مسجّلًا بدلاً من TTS — مناسب لتحية مُنتَجة، ويتجاوز
تأخّر التركيب الصوتيّ. ارفع الملفّ أوّلًا، ثم أشِر إلى `audio_ref` المُعاد.

`POST /v1/callflows/audio` يأخذ ملفّ **WAV** مُرمَّزًا بـ base64 (يُوصى بـ 8 kHz أحاديّ
16-bit PCM — جودة الهاتف) ويُعيد `audio_ref` مُستضافًا لدى Wave:

```bash cURL theme={null}
curl -X POST https://api.wave.sa/v1/callflows/audio \
  -H "Authorization: Bearer sk_live_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "base64": "<base64-wav>", "content_type": "audio/wav", "file_name": "welcome.wav" }'
```

```json theme={null}
{ "audio_ref": "https://<bucket>.<region>.aliyuncs.com/prompts/<org>/<id>.wav" }
```

استخدم `audio_ref` في `play`:

```json theme={null}
{ "prompt": { "play": { "audio_ref": "https://…/prompts/<org>/<id>.wav" } } }
```

<Note>
  رفع الملفّات الصوتيّة قيد الإطلاق. حتّى تفعيله لحسابك، يُعيد الرفع `503` وتستخدم
  القوائم تحيات `say` (TTS). يجب أن يكون `audio_ref` ملفًّا رفعته **أنت** — تُرفض
  الروابط العشوائيّة.
</Note>

## الخطوات التالية

* [WaveML](/ar/voice/waveml) — الأوامر التي تُترجَم إليها القائمة، والمسارات المخصّصة الكاملة.
* [Webhooks](/ar/webhooks) — استقبال `call.input` والتحقّق منه.
* [الطوابير](/ar/voice/queues) — حيث يُرسل فرع `enqueue` المتّصل.
