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

# الحملات

> اتّصل بقائمة من المستلمين تلقائيًّا: تنظّم Wave وتيرة المكالمات، وتعيد المحاولة مع من لم يردّ، وتخبرك بنتيجة كلّ مستلم.

تتّصل **الحملة** بقائمة من المستلمين نيابةً عنك. تعطي Wave الأرقام، ومسار مكالمة
محفوظًا، ومعرّف متّصل. تتّصل Wave بكلّ مستلم، وتعيد المحاولة مع من لم يردّ، وتشغّل
كشف جهاز الرد الآلي على كلّ مكالمة مُجابة. يسمع الشخص مسار المكالمة الخاصّ بك.
ويتلقّى جهاز الرد الآلي رسالة البريد الصوتي، إن حدّدتها.

> [!NOTE]
>
> تُطرح الحملات خلف مفتاح تفعيل لكلّ بيئة. وإلى أن تُفعَّل في بيئتك تُعيد كلّ نقطة
> نهاية `503 CAMPAIGNS_DISABLED`. تشغّل الحملة مسار مكالمة محفوظًا، لذا يحتاج
> الإنشاء أيضًا إلى [مسارات المكالمة المحفوظة](https://docs.wave.sa/ar/voice/ivr.md) في بيئتك. ومن دونها
> يُعيد الإنشاء `409 CAMPAIGN_NEEDS_IVR`.

## أنشئ حملة

ينشئ `POST /v1/campaigns` حملة. يتطلّب النطاق `campaigns:write`. أرسل الترويسة
`Idempotency-Key`: إعادة الطلب بالمفتاح نفسه تُعيد الحملة الأولى ولا تنشئ حملة
ثانية. تحتفظ Wave بالمفتاح 24 ساعة. ولا يُحفظ الطلب المرفوض.

```bash cURL theme={null}
curl -X POST https://api.wave.sa/v1/campaigns \
  -H "Authorization: Bearer $WAVE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: renewals-2026-11-02" \
  -d '{
    "name": "Policy renewals",
    "callflow_name": "renewal-menu",
    "caller_id": "+966590007001",
    "recipients": [
      { "phone": "+966500000001", "reference": "policy-1001" },
      { "phone": "+966500000002", "reference": "policy-1002" }
    ],
    "start_at": "2026-11-02T09:00:00+03:00",
    "calling_window": { "start": "09:00", "end": "17:00" },
    "max_attempts": 3,
    "retry_after_minutes": 30,
    "max_concurrent": 5,
    "voicemail_message": {
      "type": "say",
      "text": "حان موعد تجديد وثيقتك. يرجى معاودة الاتّصال بنا.",
      "language": "ar"
    }
  }'
```

```javascript Node.js theme={null}
const res = await fetch("https://api.wave.sa/v1/campaigns", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.WAVE_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": "renewals-2026-11-02",
  },
  body: JSON.stringify({
    name: "Policy renewals",
    callflow_name: "renewal-menu",
    caller_id: "+966590007001",
    recipients: [
      { phone: "+966500000001", reference: "policy-1001" },
      { phone: "+966500000002", reference: "policy-1002" },
    ],
    start_at: "2026-11-02T09:00:00+03:00",
    calling_window: { start: "09:00", end: "17:00" },
    max_attempts: 3,
    retry_after_minutes: 30,
    max_concurrent: 5,
    voicemail_message: {
      type: "say",
      text: "حان موعد تجديد وثيقتك. يرجى معاودة الاتّصال بنا.",
      language: "ar",
    },
  }),
});
console.log(await res.json());
```

الاستجابة `201` مع الحملة، ومعها عددان: `recipients_accepted` و`duplicates_removed`.

```json theme={null}
{
  "id": "5b1c…",
  "name": "Policy renewals",
  "status": "scheduled",
  "callflow_name": "renewal-menu",
  "caller_id": "+966590007001",
  "start_at": "2026-11-02T06:00:00.000Z",
  "calling_window": { "start": "09:00", "end": "17:00" },
  "max_attempts": 3,
  "retry_after_minutes": 30,
  "max_concurrent": 5,
  "voicemail_message": {
    "type": "say",
    "text": "حان موعد تجديد وثيقتك. يرجى معاودة الاتّصال بنا.",
    "language": "ar"
  },
  "sandbox": false,
  "created_at": "2026-10-30T10:00:00.000Z",
  "started_at": null,
  "completed_at": null,
  "recipients_accepted": 2,
  "duplicates_removed": 0
}
```

### الحقول

| الحقل | مطلوب | القواعد |
| - | - | - |
| `name` | نعم | من 1 إلى 100 حرف. |
| `callflow_name` | نعم | من 1 إلى 100 حرف. اسم مسار مكالمة محفوظ في حسابك. يجب أن يكون [قائمة أو قائمة متعدّدة المستويات](https://docs.wave.sa/ar/voice/ivr.md). |
| `caller_id` | للإنتاج فقط | رقم سعودي يملكه حسابك. يتجاهله مفتاح الـ sandbox. |
| `recipients` | نعم | من 1 إلى 10,000 مستلم (5 مع مفتاح الـ sandbox). لكلّ مستلم `phone` سعودي و`reference` اختياري (64 حرفًا كحدّ أقصى). لا تنطق Wave قيمة `reference` أبدًا. |
| `start_at` | لا | وقت بصيغة ISO 8601 مع فرق التوقيت. من دون `start_at`، أو مع وقت في الماضي، تبدأ الحملة فورًا (`running`). والوقت المستقبلي يعطي `scheduled`. |
| `calling_window` | لا | `{ "start": "HH:MM", "end": "HH:MM" }` بتوقيت السعودية. تتّصل Wave داخل هذه النافذة اليومية فقط. يمكن أن تتجاوز النافذة منتصف الليل؛ ويجب أن يختلف `start` عن `end`. ومن دون نافذة، تتّصل Wave في أيّ وقت من اليوم. |
| `max_attempts` | لا | من 1 إلى 5. القيمة الافتراضية `3`. |
| `retry_after_minutes` | لا | من 10 إلى 1440. القيمة الافتراضية `30`. |
| `max_concurrent` | لا | أكبر عدد من مكالمات هذه الحملة في الوقت نفسه. القيمة الافتراضية: نصف حدّ التزامن لحسابك (1 على الأقلّ). الحدّ الأقصى هو حدّ التزامن − 1 (1 على الأقلّ)، ليبقى خطّ واحد حرًّا لمكالماتك الأخرى. |
| `voicemail_message` | لا | ما يتلقّاه جهاز الرد الآلي. `{ "type": "say", "text": "…", "language": "ar" }` (النصّ 500 حرف كحدّ أقصى؛ و`language` هي `ar` أو `en`)، أو `{ "type": "play", "url": "https://…" }` (رابط ملفّ صوتي عامّ بـ HTTPS). |
| `environment` | لا | `sandbox` أو `production`. ينشئ المفتاح حملة في بيئته. والقيمة التي ليست بيئة المفتاح تُعيد `400`. |

يمكن أن يبلغ جسم الطلب 2 MB كحدّ أقصى. تحذف Wave أرقام الهاتف المكرّرة: يبقى أوّل
صفّ للرقم.

### الـ sandbox والإنتاج

* **مفتاح الـ sandbox:** 5 مستلمين كحدّ أقصى. تعرض الحملة دائمًا رقم الـ sandbox
  المشترك، وتتجاهل Wave قيمة `caller_id`.
* **مفتاح الإنتاج:** `caller_id` مطلوب. الرقم الذي لا يملكه حسابك يُعيد
  `403 CLI_NOT_OWNED`.

### فعّل مسار المكالمة أوّلًا

> [!WARNING]
>
> يسمع الشخص **الإصدار النشط** من مسار المكالمة. يقبل الإنشاء مسار مكالمة ليس له
> إصدار نشط. وعندها تنتهي كلّ مكالمة مُجابة ولا يسمع الشخص شيئًا، لكنّ النتيجة تبقى
> `answered`. [فعّل إصدارًا](https://docs.wave.sa/ar/voice/ivr.md) من مسار المكالمة قبل أن تبدأ الحملة.

## كيف تتّصل Wave

* **الوتيرة.** تبدأ Wave مكالمات جديدة فقط ما دامت الحملة أقلّ من `max_concurrent`،
  وحسابك أقلّ من حدّ التزامن، و[حدود المكالمات](https://docs.wave.sa/ar/voice/calls-and-recordings.md#حدود-معدّل-المكالمات)
  تسمح بمكالمة جديدة. عندما توقف حدود المكالمات مكالمة، أو عندما تكون المكالمات
  الصادرة معلّقة على حسابك، ينتظر المستلم محاولة لاحقة. ولا تحتسب Wave محاولة.
* **متى.** تتّصل Wave بدءًا من `start_at`، وداخل نافذة الاتّصال فقط (بتوقيت
  السعودية). وخلال ساعات الهدوء، تنتظر المكالمة حتّى تنتهي ساعات الهدوء.
* **الأرقام التي ألغت الاشتراك.** لا تتّصل Wave بمستلم ألغى اشتراكه. ونتيجته
  `skipped`.
* **عند كلّ ردّ.** يعمل كشف جهاز الرد الآلي أوّلًا:
  * شخص (أو لم تكن Wave متأكّدة): يسمع الشخص مسار المكالمة الخاصّ بك.
  * جهاز رد آلي، مع رسالة بريد صوتي: تنتظر Wave صوت التنبيه (الصفارة)، ثم تشغّل
    الرسالة أو تنطقها، ثم تُنهي المكالمة. وإذا لم يأتِ صوت التنبيه، تشغّل Wave
    الرسالة أيضًا ثم تُنهي المكالمة.
  * جهاز رد آلي، من دون رسالة بريد صوتي: تُنهي Wave المكالمة.

## النتائج وإعادة المحاولة

ينتهي كلّ مستلم بنتيجة واحدة:

| النتيجة | المعنى |
| - | - |
| `answered` | ردّ شخص (أو لم تكن Wave متأكّدة). |
| `voicemail` | ردّ جهاز رد آلي. |
| `no_answer` | لم يردّ أحد، بعد آخر محاولة. |
| `busy` | كان الخطّ مشغولًا، بعد آخر محاولة. |
| `failed` | تعذّر إجراء المكالمة أو توصيلها. |
| `skipped` | ألغى المستلم اشتراكه. لم تتّصل Wave. |
| `cancelled` | أُوقفت الحملة قبل أن ينتهي المستلم. |

**إعادة المحاولة:** بعد `no_answer` أو `busy` أو `failed`، تحاول Wave مرّة أخرى بعد
`retry_after_minutes`، حتّى يصل المستلم إلى `max_attempts` محاولة. وعندها تصبح
تلك النتيجة نهائية. وفي حالتين تكون النتيجة `failed` فورًا، من دون إعادة محاولة:

* لم يرسل المحرّك الصوتي أيّ إشارة عن المكالمة بعد 5 دقائق من إرسال Wave لها.
* رفضت Wave أو المحرّك الصوتي المكالمة، أو ألغاها المحرّك الصوتي.

## الإيقاف المؤقّت والاستئناف والإيقاف

للحملة إحدى هذه الحالات:

| الحالة | المعنى |
| - | - |
| `scheduled` | تنتظر `start_at`. |
| `running` | تُجري Wave المكالمات. |
| `paused` | لا تُجري Wave مكالمات جديدة. |
| `stopped` | أوقفتها أنت. لا يمكن التراجع عن ذلك. |
| `completed` | لكلّ مستلم نتيجة. |

استخدم `POST /v1/campaigns/{id}/pause` و`/resume` و`/stop`. يتطلّب كلّ منها النطاق
`campaigns:write` ويُعيد الحملة.

| الإجراء | من | إلى |
| - | - | - |
| `pause` | `running` | `paused` |
| `resume` | `paused` | `running` |
| `stop` | `scheduled` أو `running` أو `paused` | `stopped` |

أيّ انتقال آخر يُعيد `409 CAMPAIGN_INVALID_STATE`. عند الإيقاف المؤقّت أو الإيقاف،
تستمرّ المكالمات الجارية حتّى نهايتها. ويعطي الإيقاف النتيجة `cancelled` لكلّ
مستلم لم ينتهِ بعد.

```bash cURL theme={null}
curl -X POST https://api.wave.sa/v1/campaigns/5b1c…/pause \
  -H "Authorization: Bearer $WAVE_API_KEY"
```

```javascript Node.js theme={null}
const res = await fetch("https://api.wave.sa/v1/campaigns/5b1c…/pause", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.WAVE_API_KEY}`,
  },
});
console.log(await res.json());
```

## اقرأ حملة ومستلميها

تتطلّب كلّ عمليات القراءة النطاق `campaigns:read`. يرى مفتاح الـ sandbox حملات
الـ sandbox فقط، ويرى مفتاح الإنتاج حملات الإنتاج فقط.

* يعرض `GET /v1/campaigns` حملات المشروع، الأحدث أوّلًا، كصفحة بمؤشّر (`limit`
  افتراضيًّا 20، و100 كحدّ أقصى).
* يُعيد `GET /v1/campaigns/{id}` الحملة مع `counts` (`total` و`by_state`
  و`by_outcome`) و`estimated_cost_sar`. التكلفة تقدير فقط: قد تختلف الفوترة.
* يعرض `GET /v1/campaigns/{id}/recipients` المستلمين، الأحدث أوّلًا، كصفحة بمؤشّر
  (`limit` افتراضيًّا 50، و100 كحدّ أقصى). صفِّ النتائج بـ `?outcome=`.

```bash cURL theme={null}
curl "https://api.wave.sa/v1/campaigns/5b1c…/recipients?outcome=no_answer&limit=50" \
  -H "Authorization: Bearer $WAVE_API_KEY"
```

```javascript Node.js theme={null}
const res = await fetch(
  "https://api.wave.sa/v1/campaigns/5b1c…/recipients?outcome=no_answer&limit=50",
  {
    headers: {
      Authorization: `Bearer ${process.env.WAVE_API_KEY}`,
    },
  }
);
console.log(await res.json());
```

```json theme={null}
{
  "data": [
    {
      "id": "c07e…",
      "phone": "+966500000002",
      "reference": "policy-1002",
      "state": "done",
      "outcome": "no_answer",
      "attempts": 3,
      "next_attempt_at": null,
      "last_call_id": "27d6dd39-…",
      "machine_detection_result": null,
      "updated_at": "2026-11-02T10:05:00.000Z"
    }
  ],
  "next_cursor": null,
  "limit": 50
}
```

أعِد `next_cursor` كـ `?cursor=` لتحصل على الصفحة التالية. حالة المستلم `state` هي
`pending` أو `waiting` أو `dialling` أو `done`. وقيمة `machine_detection_result` هي
`human` أو `machine` أو `notsure`، أو `null` إذا لم يعمل الكشف.

## الـ Webhooks

اشترك في حدثَي [webhook](https://docs.wave.sa/ar/webhooks.md) بدلًا من الاستعلام المتكرّر. لا يحمل الحدثان
**أيّ رقم هاتف**: طابِق على `reference` أو `recipient_id`.

`campaign.recipient_completed` — حصل مستلم على نتيجته النهائية:

```json theme={null}
{
  "event": "campaign.recipient_completed",
  "data": {
    "campaign_id": "5b1c…",
    "recipient_id": "c07e…",
    "reference": "policy-1002",
    "outcome": "voicemail",
    "attempts": 1,
    "last_call_id": "27d6dd39-…",
    "machine_detection_result": "machine"
  }
}
```

`campaign.completed` — لكلّ مستلم نتيجة (`status: "completed"`)، أو أوقفت أنت
الحملة (`status: "stopped"`). تذكر `by_outcome` كلّ النتائج، مع `0` للنتيجة غير
الموجودة:

```json theme={null}
{
  "event": "campaign.completed",
  "data": {
    "campaign_id": "5b1c…",
    "status": "completed",
    "counts": {
      "total": 2,
      "by_outcome": {
        "answered": 1,
        "voicemail": 1,
        "no_answer": 0,
        "busy": 0,
        "failed": 0,
        "skipped": 0,
        "cancelled": 0
      }
    }
  }
}
```

## الأخطاء

| الحالة | الرمز | متى |
| - | - | - |
| `400` | `VALIDATION_ERROR` | حقل يخالف قاعدة أعلاه. تذكر الرسالة اسم الحقل. |
| `403` | `CLI_NOT_OWNED` | `caller_id` ليس رقمًا يملكه حسابك. |
| `403` | `INSUFFICIENT_PERMISSIONS` | لا يحمل المفتاح النطاق `campaigns:read` أو `campaigns:write`. |
| `404` | `CAMPAIGN_NOT_FOUND` | لا توجد هذه الحملة في مشروعك وبيئتك. |
| `409` | `CAMPAIGN_INVALID_STATE` | لا تستطيع الحملة إجراء هذا الانتقال من حالتها. |
| `409` | `CAMPAIGN_LIMIT_REACHED` | يمكن لحسابك أن يضمّ 50,000 مستلم لم ينتهوا بعد كحدّ أقصى، في كلّ حملاته. لا تُحتسب الحملات الموقوفة والمكتملة. |
| `409` | `CAMPAIGN_NEEDS_IVR` | مسارات المكالمة المحفوظة غير مفعّلة في هذه البيئة. |
| `503` | `CAMPAIGNS_DISABLED` | الحملات غير مفعّلة في هذه البيئة. |

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

> **[قوائم الرد الصوتي](https://docs.wave.sa/ar/voice/ivr.md)**
>
> أنشئ مسار المكالمة الذي يسمعه الشخص.

> **[الـ Webhooks](https://docs.wave.sa/ar/webhooks.md)**
>
> احصل على كلّ نتيجة فور حدوثها بدلًا من الاستعلام المتكرّر.


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