
# واجهة برمجة التطبيقات (API) للوكالات

بصفتك وكالة، يمكنك استخدام نفس REST API الذي يستخدمه عملاؤك، ولكن يمكنك توجيه الطلبات الفردية إلى أحد **الحسابات الفرعية** التي تديرها بدلاً من حسابك الخاص. يتيح لك هذا بناء أدوات تقوم بتهيئة العميل من البداية إلى النهاية — إنشاء حملاتهم، وتدريب ذكائهم الاصطناعي على قاعدة معرفية، واستيراد جهات اتصالهم، وربط قنوات المراسلة الخاصة بهم، وشراء أرقام هواتف — كل ذلك دون الحاجة إلى تسجيل الدخول إلى كل حساب فرعي يدويًا.

تغطي هذه الصفحة السلوك الخاص بالوكالة فقط: كيفية التصرف نيابة عن حساب فرعي باستخدام المعامل `sub_account_id`. للاطلاع على الأساسيات (إنشاء مفتاح، المصادقة، عنوان URL الأساسي، تنسيق الخطأ، حدود المعدل)، ابدأ بدليل [الوصول إلى واجهة برمجة التطبيقات](../integrations/api-access.md). كل ما ورد هناك ينطبق هنا أيضاً — حيث تقوم بالمصادقة باستخدام مفتاح واجهة برمجة التطبيقات الخاص **بحساب وكالتك**.

::: note
**ملاحظة:** هذه الصفحة تقنية. إذا لم تكن مطوراً، شاركها مع الشخص الذي يقوم ببناء التكامل الخاص بك.
:::


***

## كيف يعمل "التصرف نيابة عن"

بشكل افتراضي، يعمل كل طلب لواجهة برمجة التطبيقات على الحساب الذي يمتلك مفتاح واجهة برمجة التطبيقات — وهو حساب وكالتك. للتصرف نيابة عن حساب عميل مُدار بدلاً من ذلك، أضف المعامل الاختياري `sub_account_id` إلى الطلب، وقم بتعيينه على معرف حساب ذلك العميل.

- **حذف `sub_account_id`** ← يعمل الطلب على حساب وكالتك الخاص.
- **تضمين `sub_account_id`** ← يعمل الطلب على ذلك الحساب الفرعي، ولكن فقط بعد أن تؤكد المنصة أن الحساب الفرعي يخصك بالفعل.

أنت تقوم دائماً بالمصادقة باستخدام مفتاح واجهة برمجة التطبيقات الخاص **بحساب وكالتك**. لا تحتاج أبداً إلى مفتاح الحساب الفرعي الخاص، ولا تتعامل أبداً مع بيانات اعتماد الحساب الفرعي.

### أين تضعه

- **نقاط نهاية GET / DELETE** → مررها كمعامل استعلام: `?sub_account_id=THE_SUB_ACCOUNT_ID` (إلى جانب `apiKey` الخاص بك، إذا كنت تقوم بالمصادقة عبر الاستعلام).
- **نقاط نهاية POST / PUT / PATCH** → قم بتضمينها في نص طلب JSON كـ `"sub_account_id": "THE_SUB_ACCOUNT_ID"`.
- **مساعدو الذكاء الاصطناعي** → لا يوجد شيء يحتاج إلى تهيئة. يحمل [خادم MCP](../integrations/connect-ai-clients.md) نفس الإعداد في أدوات القراءة الخاصة به، لذا يمكن لاتصال واحد باستخدام مفتاح الوكالة الخاص بك تقديم تقارير عن كل عميل: ما عليك سوى ذكر اسم العميل في طلبك ("كم عدد جهات الاتصال لدى Bella's Bistro؟"). إجراءات الكتابة متاحة أيضاً: كل نقطة نهاية تقبل `sub_account_id` يتم عرضها كأداة، لذا يمكنك الإنشاء والتغيير والإرسال نيابة عن العميل من نفس الاتصال.

### العثور على معرف الحساب الفرعي

يُعد `sub_account_id` المعرف الفريد لحساب العميل. يمكنك الحصول على قائمة الحسابات الفرعية الخاصة بك ومعرفاتها من نقاط نهاية واجهة برمجة تطبيقات **SubAccounts** (راجع دليل [الحسابات الفرعية](sub-accounts.md)) أو من صفحة **الحسابات الفرعية** في الشريط الجانبي.

***

## يتم التحقق من الملكية دائماً

عند تمرير `sub_account_id`، تتحقق المنصة من أن الحساب هو حساب فرعي حقيقي **و** أنه ينتمي إلى وكالتك. عندها فقط يتم تنفيذ الطلب.

إذا كان المعرف غير معروف، أو لم يكن حساباً فرعياً، أو ينتمي إلى وكالة أخرى، يفشل الطلب مع استجابة **`404`**:

```json
{
  "success": false,
  "error_code": 404,
  "error": "Sub-account not found."
}
```

> **لماذا 404 وليس 403؟** إن استجابة "ممنوع" (forbidden) ستخبر الطرف الخارجي بأن المعرف (id) موجود ولكنه لا يخصه. إرجاع نفس `404` لكل من "غير موجود" و"لا يخصك" يعني أنه لا يمكن استخدام نقطة النهاية لاكتشاف معرفات الحسابات التي تنتمي إلى وكالات أخرى. تعامل مع `404` هنا على أنه "هذا ليس حساباً فرعياً تديره".

***

## أين يتم دعم `sub_account_id`

يتم قبول `sub_account_id` في كل نقطة نهاية **للموارد** تقريبًا — أي استدعاء يقوم بإنشاء أو قراءة أو تحديث أو حذف بيانات الحساب نفسه. من الناحية العملية، يمكنك توفير وتشغيل إعدادات الحساب الفرعي بالكامل باستخدام مفتاح الوكالة الخاص بك:

- **إعداد الذكاء الاصطناعي** — الحملات، الوكلاء، الأسئلة الشائعة، مصادر القاعدة المعرفية (زحف الموقع الإلكتروني **و** تحميل المستندات)، مجموعات القاعدة المعرفية، البث، الوظائف المخصصة، خوادم MCP
- **جهات الاتصال وإدارة علاقات العملاء (CRM)** — جهات الاتصال (بما في ذلك الاستيراد)، القوائم، العلامات، المهام، الصفقات، المواعيد، الأحداث
- **القنوات والأرقام** — ربط WhatsApp / WhatsApp Web / Telegram / Instagram & Messenger / LINE، البحث عن / شراء / إدارة أرقام الهواتف، قوالب WhatsApp، توجيه القنوات
- **المراسلة والمحتوى** — إرسال الرسائل، جلسات الدردشة، تصدير الدردشات، الملخصات اليومية
- **الإعدادات والتكاملات** — خطافات الويب (webhooks)، تكوين أداة الدردشة، تكوين العلامة البيضاء (white-label)، رسائل SMS الخاصة بك (BYOK) وإعدادات الحساب الأخرى، التحليلات

في كل واحدة من هذه الحالات، يكون المعامل **اختياريًا** — اتركه فارغًا وسيعمل الاستدعاء على حساب الوكالة الخاص بك، بحيث يخدم تكامل واحد كلا الطرفين. يتم خصم الأرصدة والاستخدام دائمًا من الحساب الذي تستهدفه: الرسوم الخاصة بحملات الحساب الفرعي، والرسائل، والعلامات، والأرقام يتم خصمها من رصيد **الحساب الفرعي**.

### الحالات التي لا ينطبق فيها ذلك

بعض نقاط النهاية تكون على مستوى الوكالة أو موجهة للذات وتتجاهل `sub_account_id`:

- **إدارة الحسابات الفرعية نفسها** — نقاط نهاية الحسابات الفرعية (إنشاء / سرد / تحديث حساب فرعي) ونقطة نهاية حد الإنفاق الخاص بـ BYOK تسمي بالفعل الحساب الفرعي في مسار URL الخاص بها. تتبع [نقاط نهاية التسعير والسياسة](#set-per-client-ai-pricing-and-policy) و[نقاط نهاية مراقبة الدردشة](#read-a-sub-accounts-conversations) النمط نفسه.
- **نسخ وكيل (Agent) بين الحسابات** — تقوم `POST /v1/subaccounts/agents/copy` بتسمية كلا الحسابين، حيث تأخذ الوجهة كـ `targetUserId`. انظر [المثال العملي](#worked-example-ship-a-template-agent-into-every-new-client) أدناه. (تعمل `POST /v1/subaccounts/campaigns/copy` الأقدم بنفس الطريقة ولكن تم إيقافها مع بقية [واجهة برمجة تطبيقات الحملات](../api/campaigns.md).)
- **تعديل الأرصدة، وعمليات التجميع على مستوى الوكالة** — تحدد [`POST /v1/subaccounts/credits`](#grant-or-deduct-credits-directly) الحساب الفرعي بواسطة `email` بدلاً من ذلك؛ بينما تقوم [`GET /v1/subaccounts/credit-usage`](#read-credit-usage-and-campaign-health-across-your-book) و `GET /v1/subaccounts/campaign-status` بإعداد تقارير عن كل حساب فرعي في وقت واحد، لذا لا يوجد حساب واحد للاستهداف.
- **حساب وكالتك الخاص** — إدارة مفاتيح API، وإعداد تقارير استخدام الوكالة، وإدارة الفريق، و[مستويات التسعير](#manage-your-pricing-tiers-over-the-api) الخاصة بك تعمل دائمًا على حساب وكالتك.
- **خطافات الويب للرسائل الواردة** — نقاط النهاية التي تنشر فيها الأنظمة الخارجية *إلى* مرتبطة بالحساب الذي قامت بيانات اعتماده بتهيئتها، لذا لا يوجد شيء لإعادة توجيهه.

> القائمة المحدثة دائمًا والقابلة للقراءة آليًا للمعلمات التي تقبلها كل نقطة نهاية موجودة في مرجع واجهة برمجة التطبيقات الخاص بلوحة التحكم (**الإعدادات ← عمليات التكامل ← مفتاح واجهة برمجة التطبيقات**) ومواصفات OpenAPI على `GET /v1/docs/openapi.yaml`. نحن نصدر تغييرات واجهة برمجة التطبيقات بشكل متكرر - تعامل معها كمصدر أساسي للمعلومات.

::: master-only
<figure><img src="../.gitbook/assets/v2-api-access-key-section.png" alt="صفحة إعدادات مفتاح API مع مفتاح مخفي وعنصر تحكم إعادة التوليد"><figcaption><p>الإعدادات ← عمليات التكامل ← مفتاح API — مفتاح وكالتك موجود هنا، بجانب رابط مرجع API الكامل.</p></figcaption></figure>
:::

***

## مثال عملي: ربط Instagram و Messenger لحساب فرعي

يعد ربط Instagram و Messenger تدفقاً يعتمد على المتصفح. تبدأ العملية باستخدام API، ثم تسلم رابط الموافقة الذي تم إرجاعه للعميل (أو تفتحه له)، وتنتظر حتى يقوم بالتفويض في متصفحه، ثم تختار الصفحة التي تريد ربطها — كل ذلك أثناء استهداف حسابه الفرعي باستخدام `sub_account_id`.

### الخطوة 1 — بدء الاتصال

استدعِ نقطة نهاية الاتصال مع `sub_account_id` الخاص بالعميل في body. لا يتم إرسال أي بيانات اعتماد هنا؛ تُرجع المنصة رابط موافقة يجب على العميل فتحه في المتصفح، بالإضافة إلى رمز ارتباط (correlation token) لمرة واحدة.

**cURL**

```bash
curl -X POST "https://api.dmchamp.com/v1/channels/meta/connect?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sub_account_id": "abc123def456"
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.dmchamp.com/v1/channels/meta/connect", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    sub_account_id: "abc123def456",
  }),
});

const data = await res.json();
// data.oauth_url -> open this in the client's browser
```

**Python**

```python
import requests

res = requests.post(
    "https://api.dmchamp.com/v1/channels/meta/connect",
    headers={
        "X-API-Key": "YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={
        "sub_account_id": "abc123def456",
    },
)

data = res.json()
# data["oauth_url"] -> open this in the client's browser
```

**الاستجابة:**

```json
{
  "success": true,
  "oauth_url": "https://www.facebook.com/v21.0/dialog/oauth?client_id=...&state=...",
  "state_token": "8sFq2yV0kQ7m4n1pZr3tWb6cXe9hJl2aD5gK7uN0oI",
  "expires_at": "2026-06-10T12:30:00.000Z"
}
```

أرسل العميل إلى `oauth_url` في المتصفح للتفويض. يقوم `state_token` بربط هذه المحاولة وهو سر قصير الأجل — لا تقم بتسجيله. تنتهي صلاحية المحاولة في `expires_at`؛ إذا انقضت، ابدأ من جديد.

### الخطوة 2 — الاستطلاع (Polling) حتى تحميل الصفحات

بعد أن يقوم العميل بالتفويض، قم باستطلاع نقطة نهاية الحالة (باستخدام نفس `sub_account_id`، هذه المرة كمعامل استعلام) حتى تظهر الصفحات القابلة للاتصال.

**cURL**

```bash
curl "https://api.dmchamp.com/v1/channels/meta/status?apiKey=YOUR_API_KEY&sub_account_id=abc123def456"
```

**JavaScript**

```javascript
const res = await fetch(
  "https://api.dmchamp.com/v1/channels/meta/status?sub_account_id=abc123def456",
  { headers: { "X-API-Key": "YOUR_API_KEY" } }
);

const data = await res.json();
// Wait until data.status === "pages_loaded", then read data.pages
```

**Python**

```python
import requests

res = requests.get(
    "https://api.dmchamp.com/v1/channels/meta/status",
    headers={"X-API-Key": "YOUR_API_KEY"},
    params={"sub_account_id": "abc123def456"},
)

data = res.json()
# Wait until data["status"] == "pages_loaded", then read data["pages"]
```

**الاستجابة:**

```json
{
  "success": true,
  "status": "pages_loaded",
  "pages": [
    {
      "id": "1098765432101234",
      "name": "Acme Studio",
      "category": "Hair Salon",
      "instagram_business_account": {
        "id": "17841400000000000",
        "username": "acme.studio"
      }
    }
  ],
  "selected_page": null
}
```

ينتقل الحقل `status` عبر `pending` ← `token_received` ← `pages_loaded` ← `connected`. انتظر `pages_loaded` قبل اختيار صفحة. يمكن أن تظهر حالتا خطأ نهائيتان أيضًا بدلاً من التقدم: `failed` و `expired` (رفض العميل الموافقة، أو انقضاء نافذة رمز الحالة التي تبلغ حوالي 30 دقيقة) — يتم تضمين حقل `reason` عند حدوث أي منهما. توقف عن الاستطلاع وأعد البدء من الخطوة 1 إذا رأيت إحداهما؛ لا تنتظر `pending` إلى الأبد. لا يتم إرجاع رموز وصول الصفحة مطلقًا.

### الخطوة 3 — اختر الصفحة المراد توصيلها

اختر أحد معرفات الصفحات من الخطوة 2 وقم بتحديده. يؤدي اختيار صفحة إلى توصيل كل من Instagram وMessenger لتلك الصفحة. قم بتضمين `sub_account_id` في النص الأساسي (body) مرة أخرى.

**cURL**

```bash
curl -X POST "https://api.dmchamp.com/v1/channels/meta/select-page?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "page_id": "1098765432101234",
    "sub_account_id": "abc123def456"
  }'
```

**JavaScript**

```javascript
const res = await fetch("https://api.dmchamp.com/v1/channels/meta/select-page", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    page_id: "1098765432101234",
    sub_account_id: "abc123def456",
  }),
});

const data = await res.json();
```

**Python**

```python
import requests

res = requests.post(
    "https://api.dmchamp.com/v1/channels/meta/select-page",
    headers={
        "X-API-Key": "YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={
        "page_id": "1098765432101234",
        "sub_account_id": "abc123def456",
    },
)

data = res.json()
```

**الاستجابة:**

```json
{
  "success": true,
  "page_id": "1098765432101234",
  "instagram_business_account_id": "17841400000000000"
}
```

هذا كل شيء — تم الآن توصيل Instagram وMessenger في الحساب الفرعي للعميل. لقد قمت فقط بتوفير `page_id`؛ يتم حل بيانات الاعتماد الأساسية على الخادم ولا يتم تمريرها مطلقاً عبر تكاملك.

***

## مثال عملي: شراء رقم لحساب فرعي

يعمل شراء رقم بنفس الطريقة: ابحث باستخدام `sub_account_id` في الاستعلام، ثم قم بالشراء باستخدامه في النص الأساسي. يتم خصم الرصيد من رصيد **الحساب الفرعي**، ويتم توفير الرقم على الحساب الفرعي.

**البحث (cURL):**

```bash
curl "https://api.dmchamp.com/v1/phone-numbers/available?apiKey=YOUR_API_KEY&country_code=US&sub_account_id=abc123def456"
```

**الشراء (JavaScript):**

```javascript
const res = await fetch("https://api.dmchamp.com/v1/phone-numbers", {
  method: "POST",
  headers: {
    "X-API-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    phone_number: "+14155551234",
    country_code: "US",
    display_name: "Support line",
    sub_account_id: "abc123def456",
  }),
});

const data = await res.json();
```

**الشراء (Python):**

```python
import requests

res = requests.post(
    "https://api.dmchamp.com/v1/phone-numbers",
    headers={
        "X-API-Key": "YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={
        "phone_number": "+14155551234",
        "country_code": "US",
        "display_name": "Support line",
        "sub_account_id": "abc123def456",
    },
)

data = res.json()
```

**الاستجابة:**

```json
{
  "success": true,
  "phone_number": "+14155551234",
  "channel": "whatsapp",
  "whatsapp_status": "PURCHASED",
  "outgoing_status": "PURCHASED",
  "status": "PURCHASED",
  "purchase_credits": 11.5,
  "monthly_credits": 11.5
}
```

يتم توفير الرقم في حالة `PURCHASED` ويستمر تسجيل مرسل WhatsApp في الخلفية. استطلع `GET /v1/phone-numbers/{phoneNumber}/status?sub_account_id=abc123def456` حتى تصل الحالة إلى `ONLINE` قبل الإرسال.

***

## مثال عملي: إرسال وكيل (Agent) نموذجي إلى كل عميل جديد

النمط المعتاد للوكالة هو الاحتفاظ بوكيل رئيسي واحد في حساب وكالتك، مضبوطًا بالطريقة التي تريد أن يبدأ بها كل عميل، ونسخه إلى كل حساب فرعي جديد في وقت التزويد. هذه ثلاث استدعاءات، ولا يحتاج أي شيء إلى التكرار بعد ذلك: تحتفظ النسخة بإعداداتها حتى تقوم بتغييرها.

### الخطوة 1 — نسخ الوكيل (Agent)

`POST /v1/subaccounts/agents/copy`

```bash
curl -X POST "https://api.dmchamp.com/v1/subaccounts/agents/copy?apiKey=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agentId": "YOUR_TEMPLATE_AGENT_ID",
    "targetUserId": "abc123def456",
    "newName": "Inbound Instagram Leads",
    "copyFaqs": true
  }'
```

تحمل الاستجابة معرف الوكيل الجديد في `data.agent_id`. يتم نقل الأسئلة الشائعة وقاعدة المعرفة ومكتبة الوسائط؛ بينما لا يتم نقل قوالب WhatsApp الخاصة بالحساب المصدر، والمنشورات الاجتماعية المتصلة، وجهات الاتصال بشكل متعمد. قائمة الحقول الكاملة موجودة في [واجهة برمجة تطبيقات وكلاء الذكاء الاصطناعي](../api/agents.md#copy-an-agent-into-a-sub-account-agencies).

لاحظ أن نقطة النهاية هذه تأخذ `targetUserId` بدلاً من `sub_account_id` — فهي تحدد كلا الحسابين بنفسها. الاستدعاءان أدناه يستخدمان المعامل `sub_account_id` العادي.

### الخطوة 2 — تشغيله

تصل النسخة دائمًا وهي متوقفة مؤقتًا، لذا لا يمكنها مراسلة أي شخص حتى تأمرها بذلك. هذه أيضًا هي اللحظة المناسبة لتثبيت مستوى الذكاء الاصطناعي الذي تريد أن يكون العميل عليه؛ حيث يبقى هناك، لذا لا حاجة لإعادة تطبيقه وفق جدول زمني.

```bash
curl -X PATCH "https://api.dmchamp.com/v1/agents/NEW_AGENT_ID/active?apiKey=YOUR_API_KEY&sub_account_id=abc123def456" \
  -H "Content-Type: application/json" \
  -d '{ "active": true }'

curl -X PUT "https://api.dmchamp.com/v1/agents/NEW_AGENT_ID?apiKey=YOUR_API_KEY&sub_account_id=abc123def456" \
  -H "Content-Type: application/json" \
  -d '{ "anthropic_model": "max" }'
```

لمنع العميل من تغيير المستوى بعد ذلك، [قم بقفل المستويات المسموح بها](#set-per-client-ai-pricing-and-policy) في الحساب الفرعي بدلاً من إعادة إرسال القيمة.

### الخطوة 3 — توجيه قنوات العميل إليها

تصل النسخة بدون توجيه أيضًا، لذا لا يصلها أي شيء حتى تجعلها هي المجيب على القنوات التي قام العميل بتوصيلها. استدعاء واحد لكل قناة:

```bash
curl -X PUT "https://api.dmchamp.com/v1/entry-points/channel-defaults?apiKey=YOUR_API_KEY&sub_account_id=abc123def456" \
  -H "Content-Type: application/json" \
  -d '{ "channel": "instagram", "agent_id": "NEW_AGENT_ID" }'
```

من هنا، يتم التقاط رسالة لأول مرة من جهة اتصال غير معروفة على تلك القناة بواسطة الوكيل المنسوخ تلقائيًا. انظر [توجيه قناة إلى وكيل](../api/entry-points.md#point-a-channel-at-an-agent) لمعرفة القنوات الأخرى والتوجيه لكل رقم.

> **قم بتعيين المنطقة الزمنية للعميل عند إنشاء الحساب الفرعي.** مرر `time_zone_id` في `POST /v1/subaccounts`. يتم تقييم ساعات نشاط الحملة في المنطقة الزمنية الخاصة بالحساب الفرعي، لذا فإن العميل الذي يتم إنشاؤه بدون منطقة زمنية تتم قراءة جدولته مقابل التوقيت العالمي المنسق (UTC) — وهو ما يتغير بهدوء عندما يُسمح للمساعد بالرد.

***

## تخطي معالج الإعداد لعميل تقوم بتهيئة حسابه بنفسك

`POST /v1/subaccounts`

بشكل افتراضي، في المرة الأولى التي يسجل فيها مالك حساب فرعي جديد دخوله، يتم توجيهه عبر معالج الإعداد الموجه. بالنسبة للعملاء الذين تقدم لهم الخدمة بالكامل — حيث تقوم ببناء الحملة وربط القنوات قبل أن يسجل العميل دخوله لأول مرة — قم بتمرير `guided_onboarding: false` عند إنشاء الحساب. سينتقلون إلى لوحة التحكم مباشرة، وسيتم إخفاء عنصر **معالج الإعداد** من الشريط الجانبي الخاص بهم.

```bash
curl -X POST "https://api.dmchamp.com/v1/subaccounts" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "client@example.com",
    "first_name": "Alex",
    "last_name": "Client",
    "business_name": "Client Co",
    "guided_onboarding": false,
    "usage_limits": { "monthly_credits": 500 }
  }'
```

احذف الحقل (أو أرسل `true`) وسيعمل المعالج تمامًا كما كان دائمًا، لذا لا تحتاج عمليات التكامل الحالية إلى أي تغيير. لإعادة المعالج إلى العميل لاحقًا، أعد إظهار عنصر `guided_onboarding` باستخدام `PUT /v1/subaccounts/{subAccountUid}/menu-visibility` (أدناه) — تتحكم رؤية القائمة في ما إذا كان المعالج قابلاً للوصول، بينما يتحكم `guided_onboarding` فقط في إعادة التوجيه عند تسجيل الدخول لأول مرة.

***

## إيقاف المهام أو الملخصات اليومية أو مكتبة الوسائط لعميل ما

`POST /v1/subaccounts`

يتم تفعيل هذه الميزات الثلاث لكل عميل جديد ما لم تحدد خلاف ذلك، وهي تعمل بشكل مختلف عن أي ميزة أخرى في هذا الدليل: فهي تعتمد على **إلغاء الاشتراك** (opt-out) وليس الانضمام (opt-in). لا يكفي استبعادها من `features` بمفرده، لأن قائمة `features` الخاصة بتكامل قديم لم تكن تذكرها ببساطة — فلا يمكننا التمييز بين "الوكالة أوقفت هذا" وبين "هذه القائمة كُتبت قبل وجود هذا الخيار".

لذا، صرّح بذلك صراحةً باستخدام `feature_settings`:

```bash
curl -X POST "https://api.dmchamp.com/v1/subaccounts" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "client@example.com",
    "first_name": "Alex",
    "last_name": "Client",
    "business_name": "Client Co",
    "feature_settings": {
      "tasks": false,
      "daily_summaries": false,
      "ai_media_library": true
    }
  }'
```

كل مفتاح اختياري؛ أي شيء تستبعده يظل مفعلاً. مع `tasks: false` يتوقف الذكاء الاصطناعي عن إنشاء مهام لذلك العميل ولن يتم إرسال رسائل بريد إلكتروني بعنوان "تم إنشاء مهمة جديدة"؛ ومع `daily_summaries: false` لن يتم إنشاء الملخص الليلي أو إرساله عبر البريد الإلكتروني.

يعد `feature_settings` هو الشيء الوحيد الذي يوقف هذه الميزات الثلاث عند الإنشاء. استبعادها من `features` لا يؤدي إلى أي شيء بمفرده، بغض النظر عما تبدو عليه بقية قائمتك — وهذا مقصود، حتى لا يفقد تكامل قديم هذه الميزات الثلاث بصمت.

لتغيير أي من هذا لاحقاً، أرسل قائمة `features` الكاملة إلى `PUT /v1/subaccounts/{subAccountUid}/features` — هناك، وجود الميزة في القائمة يؤدي إلى تفعيلها، وغيابها يؤدي إلى إيقافها.

***

## تسجيل دخول عملائك تلقائياً إلى حساباتهم الفرعية (SSO)

`POST /v1/subaccounts/{subAccountUid}/sso-link`

طلب واحد باستخدام مفتاح API الخاص بوكالتك يُرجع رابطاً جاهزاً للفتح يقوم بتسجيل دخول العميل مباشرة إلى حسابه الفرعي الخاص — بدون شاشة تسجيل دخول، وبدون خطوة كلمة مرور، ولا شيء إضافي لبنائه. يمكنك فتحه في علامة تبويب جديدة، أو كإعادة توجيه، أو داخل إطار iframe في منتجك الخاص.

| الحقل | مطلوب | الوصف |
|---|---|---|
| `redirect` | لا | الصفحة داخل التطبيق التي تريد أن ينتهي العميل إليها، على سبيل المثال `"/chats"` أو `"/agents"`. يتم إرجاعها كـ `deep_link_url` في الاستجابة. |
| `app_base_url` | لا | مضيف لوحة التحكم للرابط. يتم تعيينه افتراضيًا على نطاق تطبيقك ذي العلامة البيضاء (أو نطاق المنصة إذا لم يكن لديك أي منها). يجب أن يكون `https`. |

**cURL**

```bash
curl -X POST "https://api.dmchamp.com/v1/subaccounts/SUB_ACCOUNT_UID/sso-link" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "redirect": "/chats" }'
```

**الاستجابة**

```json
{
  "success": true,
  "url": "https://app.yourdomain.com/auth?redirect=%2Fchats#token=eyJhbGciOi…",
  "deep_link_url": "https://app.yourdomain.com/chats",
  "expires_at": "2026-07-22T15:04:05.000Z",
  "sub_account_uid": "SUB_ACCOUNT_UID"
}
```

كيفية استخدامه بشكل جيد:

- **قفزة واحدة.** يؤدي فتح `url` إلى تسجيل دخول العميل ونقله مباشرة إلى صفحة `redirect` في لوحة التحكم — دون الحاجة إلى شاشة تسجيل دخول أو صفحة وسيطة. تشير `deep_link_url` إلى الوجهة نفسها، وذلك للمكاملين الذين يفضلون التنقل إلى إطار معين صراحةً بعد تسجيل الدخول؛ فبمجرد وجود الجلسة، يعمل أي مسار في لوحة التحكم ضمن سياق المتصفح هذا.
- **إنشاء عند الطلب، وفتح فوري.** يحتوي الرابط على بيانات اعتماد تسجيل الدخول وتنتهي صلاحيته بعد ساعة تقريبًا. اطلبه من جانب الخادم في اللحظة التي ينقر فيها العميل، ولا تقم بتخزينه أو إرساله عبر البريد الإلكتروني أبدًا.
- ينتقل رمز تسجيل الدخول في جزء الرابط (`#…`)، والذي لا ترسل المتصفحات محتواه إلى الخوادم أبدًا، كما تتم إزالته من شريط العنوان بمجرد استخدامه.
- **حساباتك الفرعية فقط.** ترفض نقطة النهاية أي حساب لا تملكه وكالتك.
- يعرض الرابط منتهي الصلاحية خطأً واضحًا مع مسار لإعادة المحاولة — قم بإنشاء رابط جديد.

***

## إخفاء عناصر التنقل في حساب فرعي

`PUT /v1/subaccounts/{subAccountUid}/menu-visibility`

يتحكم في عناصر الشريط الجانبي والإعدادات التي يراها الحساب الفرعي — مفيد عند تضمين لوحة التحكم وتريد فقط إظهار الواجهات التي لا يغطيها منتجك بالفعل. أي شيء غير مدرج يظل مرئياً؛ أرسل `null` كقيمة كاملة لـ `menuVisibility` لإعادة تعيين كل شيء ليكون مرئياً. إخفاء عنصر يؤدي إلى إخفاء إدخال القائمة — قم بإقرانه بالميزات التي تمنحها للحساب الفرعي للتحكم الصارم.

**cURL**

```bash
curl -X PUT "https://api.dmchamp.com/v1/subaccounts/SUB_ACCOUNT_UID/menu-visibility" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "menuVisibility": {
      "side_nav": { "Dashboard": false, "Campaigns": false, "Automations": false },
      "settings_nav": { "team": false }
    }
  }'
```

**الاستجابة**

```json
{
  "success": true,
  "data": {
    "subAccountUid": "SUB_ACCOUNT_UID",
    "menuVisibility": {
      "side_nav": { "Dashboard": false, "Campaigns": false, "Automations": false },
      "settings_nav": { "team": false }
    }
  }
}
```

تقبل `side_nav` هذه المفاتيح الـ 13، والتي تطابق أسماء عناصر الشريط الجانبي: `Dashboard`، و`DailySummaries`، و`Chats`، و`Contacts`، و`Deals`، و`Tasks`، و`Automations`، و`Campaigns`، و`Appointments`، و`Settings`، و`Help`، و`CreditsCounter` (رصيد الائتمان المعروض في الشريط الجانبي) و`guided_onboarding` (معالج الإعداد). يتم قبول ثلاثة مفاتيح إضافية — `AiInsights` و`Sub Accounts` و`Agency Reselling` — ولكنها لا تؤدي أي وظيفة: حيث كانت تنطبق فقط على لوحة التحكم الكلاسيكية التي تم إيقافها، لذا فإن تعيينها ليس له أي تأثير على حساباتك الفرعية. تعني المفاتيح المفقودة أنها مرئية؛ فعند تسجيل دخولك إلى الحساب الفرعي بنفسك، يتم عرض العناصر المخفية مؤقتًا حتى تتمكن دائمًا من تغيير الإعدادات مرة أخرى.

إخفاء صفحة من القائمة لا يمنح الوصول إليها أبداً. يحتاج `Automations` إلى منح ميزة `automations` على الحساب الفرعي — إذا قمت بضبط المفتاح على `true` بدونها، فلن تظهر الصفحة. يعمل `Tasks` و `DailySummaries` بطريقة معاكسة: فهما مفعلان لكل عميل ما لم تقم بإيقافهما (راجع [إيقاف المهام أو الملخصات اليومية أو مكتبة الوسائط لعميل ما](#turn-tasks-daily-summaries-or-the-media-library-off-for-a-client)).

***

## اختر أنواع القنوات التي يمكن للعميل الاتصال بها

`PUT /v1/subaccounts/{subAccountUid}/features`

مفاتيح **أنواع القنوات** (Channel Types) التي تراها في مستوى الخطة هي معرفات ميزات عادية، لذا يمكنك تعيينها لكل عميل من خلال واجهة برمجة التطبيقات (API) بدلاً من لوحة التحكم. هذه واحدة من نقاط النهاية التي تحدد الحساب الفرعي في عنوان URL الخاص بها، لذا فهي لا تتطلب `sub_account_id`.

| معرف الميزة | القناة |
|---|---|
| `channel_chat_widget` | أداة دردشة الموقع الإلكتروني |
| `channel_whatsapp_api` | واجهة برمجة تطبيقات واتساب للأعمال |
| `channel_whatsapp_web` | واتساب ويب (رقم مرتبط برمز QR) |
| `channel_instagram` | إنستغرام |
| `channel_messenger` | فيسبوك ماسنجر |
| `channel_telegram` | تيليجرام |
| `channel_line` | لاين |
| `channel_viber` | فايبر |
| `channel_email` | صندوق بريد إلكتروني |
| `channel_sms` | الرسائل القصيرة (SMS) |
| `channel_imessage` | آي مسج (iMessage) |

```bash
curl -X PUT "https://api.dmchamp.com/v1/subaccounts/SUB_ACCOUNT_UID/features" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "features": [
      "channels_3",
      "channel_chat_widget",
      "channel_whatsapp_web",
      "channel_instagram",
      "image_understanding",
      "contact_tagging",
      "incoming_campaigns",
      "webhooks"
    ]
  }'
```

ثلاثة أمور يجب مراعاتها:

- **يحل الاستدعاء محل قائمة الميزات بالكامل.** أرسل كل ميزة يجب أن يحتفظ بها العميل، وليس فقط تلك التي تقوم بتغييرها. تعمل نفس المعرفات كـ `features` في `POST /v1/subaccounts` عند إنشاء الحساب.
- **أنواع القنوات وعدد القنوات هما بوابتان منفصلتان، وكلاهما قابل للتطبيق.** تتحكم `channels_1` / `channels_3` / `channels_unlimited` في *عدد* الاتصالات؛ بينما تتحكم معرفات `channel_*` في *الأنواع المسموح بها*. المثال أعلاه يعني "ما يصل إلى 3 اتصالات، وفقط أداة الدردشة، أو WhatsApp Web، أو Instagram".
- **إرسال معرفات `channel_*` فارغة يعني عدم وجود قيود على القنوات.** هذا هو السلوك الأصلي، ولهذا السبب لم يتأثر العملاء الحاليون عند إطلاق هذه الميزة. أرسل معرفاً واحداً أو أكثر وسيظهر كل شيء آخر كـ "مقفل" في صفحة قنوات العميل مع ملاحظة ترقية بدلاً من زر "اتصال". ستستمر القنوات التي اتصل بها العميل بالفعل في العمل.

> يتم تعيين قائمة القنوات على **مستوى الخطة**، بحيث يرثها كل عميل يشتري تلك الخطة، من خلال لوحة التحكم ضمن إعدادات خطة الوكالة الخاصة بك. تقوم نقطة النهاية هذه بتعيينها لحساب فرعي محدد.

***

## تعيين حد دقيق لعدد أعضاء الفريق للعميل

`PUT /v1/subaccounts/{subAccountUid}/limits`

توفر ميزات `team_seats_*` خطوات متدرجة محددة مسبقاً فقط (3 / 5 / 10 / غير محدود). لمنح العميل عدداً **دقيقاً** من مقاعد الفريق — 2، 7، 15، أو أي رقم آخر — قم بتعيين `usage_limits.team_seats_limit` بدلاً من ذلك. يتفوق هذا الخيار على الإعدادات المسبقة، وتفرضه المنصة عند كل دعوة، أو إضافة مباشرة، أو قبول دعوة: بمجرد الوصول إلى الحد، يتم رفض الدعوات الإضافية من جانب الخادم.

- العدد الصحيح الموجب هو الحد الأقصى الدقيق.
- `0` يعني أن أعضاء الفريق **غير مشمولين** — لا يمكن للعميل دعوة أي شخص.
- `-1` يعني غير محدود.
- `null` يمسح الحد المخصص ويعود إلى أي إعداد مسبق لـ `team_seats_*` موجود في قائمة الميزات.

خفض الحد لا يؤدي أبداً إلى إزالة أعضاء الفريق الحاليين؛ بل يمنع فقط إضافة أعضاء جدد.

```bash
curl -X PUT "https://api.dmchamp.com/v1/subaccounts/SUB_ACCOUNT_UID/limits" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "usageLimits": { "team_seats_limit": 7 }
  }'
```

يمكنك أيضاً تعيينها في وقت الإنشاء: تقبل `POST /v1/subaccounts` القيمة `usage_limits.team_seats_limit` بنفس الدلالات. لقراءة القيمة الحالية، قم بجلب الحساب الفرعي باستخدام `GET /v1/subaccounts?email=...` وانظر إلى `usage_limits.team_seats_limit` (في حال غيابها/`null` = الإعدادات المسبقة هي التي تقرر). تقوم نفس نقطة النهاية أيضاً بتحديث `credits` و `monthly_credits` و `roll_over_to_next_month` و `rollover_cap_months` و `rollover_expiry_days` و `byok_monthly_limit_usd` — أرسل فقط المفاتيح التي تريد تغييرها.

**كيف يتفاعل هذا مع حدود المقاعد في خطط SaaS.** يمكن لخطط SaaS الخاصة بك أن تحمل مخصصات مقاعد خاصة بها (يتم تعيينها في محرر الخطط — راجع [مقاعد الفريق في خطة ما](agency-accounts.md#step-3--set-up-pricing-tiers))، والتي يتم تطبيقها تلقائيًا عند اشتراك العميل. الحد الذي تعينه من خلال نقطة النهاية هذه يُحتسب كمنح **يدوي**: شراء خطة يستبدلها بمخصصات المقاعد الخاصة بالخطة نفسها (ذلك الشراء هو خيار خطة صريح)، ولكن **التجديدات الشهرية التلقائية لا تتجاوز أبدًا الحد اليدوي** — لذا فإن الاستثناء لمرة واحدة الذي تمنحه للعميل يستمر خلال دورة فوترته. مسح الحد اليدوي باستخدام `null` يعيد التحكم في الحقل إلى الخطة عند تجديدها التالي.

**حدد ما يحمله العميل بين فترات التجديد.** يوجد مفتاحان إضافيان من نوع `usage_limits` بجوار `roll_over_to_next_month`. كلاهما مقبول بواسطة `POST /v1/subaccounts` في وقت الإنشاء أيضاً، وتقوم `null` بمسح أي منهما.

| المفتاح | وظيفته |
|---|---|
| `rollover_cap_months` | عدد أشهر المخصصات التي قد يحتفظ بها العميل. رقم من 0 إلى 120، الكسور مسموح بها (`0.5` = نصف شهر). عند كل تجديد، يتم تقليص الرصيد غير المستخدم إلى ما لا يزيد عن هذا العدد مضروباً في المخصصات التي يمنحها ذلك التجديد، قبل إضافة الأرصدة الجديدة؛ `0` لا ترحل أي شيء. |
| `rollover_expiry_days` | عدد صحيح من الأيام، من 1 إلى 3650. الأرصدة التي تُترك دون استخدام لهذه المدة يتم إسقاطها عند أول تجديد بعد وصولها إلى هذا العمر. يتم الخصم دائماً من الأرصدة الأقدم أولاً، لذا فإن العميل الذي ينفق مخصصاته كل شهر لا يفقد أي شيء أبداً. |

إذا تُركت دون تعيين، يعود كلاهما إلى خطة العميل؛ القيمة المرسلة هنا تتفوق على قيمة الخطة. الأرصدة المتكررة فقط (المخصصات الشهرية وأرصدة الخطة) تخضع لها: عمليات الشحن الإضافي، وإعادة الشحن التلقائي، والإضافات لمرة واحدة لا يتم تحديد سقف لها أو تنتهي صلاحيتها أبداً. يتم تسجيل كل عملية تقليص في سجل رصيد العميل كـ **تعديل رصيد سقف الترحيل** أو **تعديل رصيد الأرصدة منتهية الصلاحية** ولا تُحتسب أبداً كاستخدام. المعادلات على مستوى الخطة هي `rollover_cap_months` و `rollover_expiry_days` في مستوى التسعير — راجع [الحقول الموجودة في مستوى التسعير](#the-fields-on-a-tier) و [تحديد سقف لما يتم ترحيله](sub-accounts.md#capping-what-rolls-over).

***

## تعيين تسعير وسياسة الذكاء الاصطناعي لكل عميل

`PUT /v1/subaccounts/{subAccountUid}/max-tier` · `/ai-tiers` · `/max-rate` · `/action-pricing` · `/insider-rate` · `/locked-bot-fields` · `/notifications` · `/zero-credit-reply`

ثمانية مفاتيح إضافية لكل عميل، إلى جانب `/limits` و `/features` و `/menu-visibility` المذكورة أعلاه. يأخذ كل منها معرف uid الخاص بالحساب الفرعي في الرابط (بدون `sub_account_id` في نص الطلب/معاملات الاستعلام — الهدف محدد بالفعل في المسار) ويتم تحديد نطاقها بنفس الطريقة: مفتاح الوكالة الخاص بك، ويجب أن ينتمي الحساب الفرعي إلى وكالتك.

**نماذج الذكاء الاصطناعي التي يمكن للعميل استخدامها**

```bash
curl -X PUT "https://api.dmchamp.com/v1/subaccounts/SUB_ACCOUNT_UID/max-tier" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "enabled": true }'
```

`{ "enabled": boolean }` تتيح للعميل الاشتراك في (أو إلغاء الاشتراك من) مستوى Max AI — بنيتنا التحتية بالسعر المدرج للمنصة. يؤدي تشغيل هذا لعميل BYOK إلى تغيير تكلفة الذكاء الاصطناعي الخاصة به من "مجانية على مفتاحي الخاص" إلى "محملة على رصيد ائتماني الخاص بي"، لذا فهو قرار متعمد لكل عميل بدلاً من كونه إعداداً افتراضياً على مستوى الوكالة.

لتقييد المستويات التي يمكن لحملات العميل ووكلائه الاختيار من بينها (بدلاً من مجرد تقييد الحد الأقصى)، استخدم `ai-tiers`:

```bash
curl -X PUT "https://api.dmchamp.com/v1/subaccounts/SUB_ACCOUNT_UID/ai-tiers" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "allowed_ai_tiers": ["standard", "economy"] }'
```

`allowed_ai_tiers` عبارة عن مصفوفة مستمدة من `standard`، و`economy`، و`max`، و`mini` — وهي تحل محل قائمة السماح الخاصة بالعميل. أرسل `null` (أو `[]`) لمسح القيد والسماح لهم باختيار أي مستوى. هذا الأمر مهم لأن الحساب الفرعي الذي يختار مستوى الذكاء الاصطناعي الخاص به يستهلك من رصيدك، لذا فهو الأداة للتحكم في النماذج التي يمكن لعميل إعادة البيع تحميلك تكاليفها.

**رد مؤقت أثناء نفاد رصيد العميل**

```bash
curl -X PUT "https://api.dmchamp.com/v1/subaccounts/SUB_ACCOUNT_UID/zero-credit-reply" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "enabled": true, "message": "Thanks for your message, we will get back to you shortly." }'
```

عندما يكون رصيد العميل (أو مجمعك) فارغاً، لا يمكن للذكاء الاصطناعي الإجابة ولا يسمع جهة الاتصال أي شيء. مع `enabled: true`، يتلقى كل جهة اتصال تراسل أثناء فترة التوقف `message` مرة واحدة (بحد أقصى 500 حرف، يتم إرسالها كما هي على كل قناة)، ويقوم الذكاء الاصطناعي بالإجابة على تلك المحادثات فعلياً بمجرد عودة الرصيد. يقوم `enabled: false` بحفظ النص المرسل لاحقاً؛ بينما يقوم `enabled: false` بدون `message` بإزالة الإعداد. نفس المفتاح الموجود في **رد مؤقت عند نفاد الرصيد** في نافذة تعديل الحساب الفرعي — انظر [رد مؤقت أثناء نفاد رصيد العميل](sub-accounts.md#a-holding-reply-while-a-client-is-out-of-credits).

**ما يدفعه العميل مقابل كل إجراء ذكاء اصطناعي، وهامش ربح رسوم WhatsApp**

طريقتان لتحديد السعر الموجه لعملائك، من الأبسط إلى الأكثر تفصيلاً:

```bash
curl -X PUT "https://api.dmchamp.com/v1/subaccounts/SUB_ACCOUNT_UID/max-rate" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "rate": 0.35 }'
```

`rate` هو السعر بالرصيد الذي يستهلكه رصيد الحساب الفرعي الخاص بك لكل إجراء ذكاء اصطناعي من طراز Max — وهو هامش الربح الذي تضعه لعملائك فوق ما تدفعه مجموعتك فعلياً. يقوم `null` بمسح التجاوز وإعادة السعر إلى قائمة أسعار المنصة. يجب أن يكون السعر على الأقل مساوياً لتكلفة إجراء Max على مجموعتك (بحيث لا يمكنك أبداً تسعير خدمة لعميل بأقل من تكلفتك) وبحد أقصى 10 أرصدة؛ سيتم رفض أي طلب خارج هذا النطاق مع إظهار الحد الأدنى المحسوب في رسالة الخطأ.

للحصول على تسعير لكل نوع إجراء بدلاً من سعر ثابت واحد، استخدم `action-pricing`:

```bash
curl -X PUT "https://api.dmchamp.com/v1/subaccounts/SUB_ACCOUNT_UID/action-pricing" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "actionPricing": {
      "AI_MESSAGE": 0.6,
      "CHAT_SUMMARY": 0.15,
      "wa_carrier_multiplier": null
    }
  }'
```

`actionPricing` عبارة عن دمج (MERGE) في خريطة العميل الحالية — المفتاح الذي لا تذكره يُترك كما كان، و `null` يقوم بإلغاء تعيين ذلك المفتاح وإعادته إلى قيمته الافتراضية. المفاتيح المعترف بها هي:

| المفتاح | الأسعار |
|---|---|
| `AI_MESSAGE` | رد الذكاء الاصطناعي |
| `AI_TOOL_USE` | استدعاء أداة الذكاء الاصطناعي |
| `EVALUATION_CALL` | تمريرة تقييم الدردشة |
| `INTERRUPTION_HANDLING` | التعامل مع مقاطعة في منتصف الرد |
| `CONTACT_TAG` | وسم جهة اتصال مخصص بواسطة الذكاء الاصطناعي |
| `CHAT_SUMMARY` | ملخص الدردشة |
| `wa_carrier_multiplier` | مضاعف ترميز مطبق على كل رسوم واتساب غير المتعلقة بالذكاء الاصطناعي التي يدفعها العميل: إيجار الرقم الشهري، رسوم التوصيل عبر المسار المُدار، وتكاليف تمرير قوالب Meta/Twilio. |

يجب أن تكون المعدلات لكل إجراء رقماً أكبر من 0 وحتى 10؛ يجب أن يكون `wa_carrier_multiplier` على الأقل `1` (لا يوجد خصم أقل من التكلفة) وحتى 10. إرسال مفتاح غير معروف، أو قيمة خارج النطاق، يؤدي إلى رفض الطلب بالكامل وتسمية كل مفتاح مخالف، لذا لا يمكن لخطأ مطبعي أن يحفظ بصمت سعراً لا يتم تطبيقه فعلياً.

إذا كنت عضواً في [Champions Circle](https://skool.com/dm-champions)، فإن `insider-rate` يمرر معدل خصم 20% الخاص بـ Max/Lead Finder إلى عميل واحد بدلاً من تطبيقه على مستوى الوكالة بالكامل:

```bash
curl -X PUT "https://api.dmchamp.com/v1/subaccounts/SUB_ACCOUNT_UID/insider-rate" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "enabled": true }'
```

يتطلب تفعيله أن يكون حساب وكالتك حاصلاً بالفعل على عضوية Circle؛ أما إيقاف تشغيله فلا يتطلب ذلك أبداً، لذا يمكن للعضو الذي انتهت عضويته دائماً إعادة العميل إلى الحالة السابقة.

**قفل أقسام من دليل تشغيل العميل**

```bash
curl -X PUT "https://api.dmchamp.com/v1/subaccounts/SUB_ACCOUNT_UID/locked-bot-fields" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "locked_bot_fields": ["instructions", "rules"] }'
```

`locked_bot_fields` عبارة عن مصفوفة مستمدة من `instructions`، `goal`، `rules`، `personality`، `conclude_unless` — وهي تحل محل قائمة العميل المقفلة. يتم رفض القسم المقفل من جانب الخادم إذا حاول الحساب الفرعي نفسه تغييره (مباشرة، أو عبر مفتاح API)، بينما لا يزال بإمكانك (عبر `sub_account_id`) وعرض مسؤول لوحة تحكم العميل تعديل أي شيء. أرسل `null` (أو `[]`) لإلغاء قفل كل شيء. مفيد للعملاء الذين تقدم لهم خدمة متكاملة حيث تمتلك أنت دليل التشغيل ويتم تقييمك بناءً على النتيجة.

**تعيين تفضيلات إشعارات العميل نيابة عنه**

```bash
curl -X PUT "https://api.dmchamp.com/v1/subaccounts/SUB_ACCOUNT_UID/notifications" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "notifications": {
      "settings": {
        "credit_alerts": { "enabled": true, "channels": ["email", "in_app"] },
        "new_contacts": { "enabled": false }
      }
    }
  }'
```

`notifications` يحل محل مجموعة تفضيلات الإشعارات الكاملة للعميل (ليس دمجاً لكل مفتاح — أرسل كل فئة تريد الاحتفاظ بها، بما يتوافق مع كيفية حفظ صفحة إعدادات الحساب الفرعي لنفسها). تقبل كل فئة تحت `settings` قيمة `enabled` (منطقية) وما يصل إلى ثلاثة `channels` من `email`، `in_app`، `webhook`. أرسل `null` لإعادة التعيين إلى إعدادات المنصة الافتراضية.

تستجيب جميع نقاط النهاية السبع بـ `{ "success": true, "data": { "subAccountUid": "...", ...the field(s) you set... } }`، ويتم تسجيلها في سجل التدقيق مع القيمة قبل/بعد التعديل. الأخطاء الشائعة: `403` إذا لم يكن حسابك وكالة/مطور أو لم يكن الحساب الفرعي خاضعاً لإدارتك، `400` إذا لم يكن حساباً فرعياً للوكالة أو كانت القيمة خارج النطاق.

***

## إيقاف عميل قام بتعليق اشتراكه

`POST /v1/subaccounts/{subAccountUid}/pause` · `POST /v1/subaccounts/{subAccountUid}/unpause`

عندما يقوم العميل بتعليق اشتراكه معك، قم بإيقاف حسابه مؤقتاً بدلاً من حذفه: سيتوقف كل ما يرسله على الفور — الرسائل الصادرة، والبث، وردود الذكاء الاصطناعي على جميع القنوات — وعندما يسجل الدخول، سيرى شاشة **الحساب متوقف مؤقتاً** (مع رسالتك الاختيارية) بدلاً من التطبيق. لا يتم حذف أو فصل أي شيء: الوكلاء، والحملات، والقنوات المتصلة، وجهات الاتصال، وسجل الدردشة، كلها تبقى كما هي تماماً، لذا فإن إلغاء الإيقاف يعيد العميل إلى النقطة التي توقف عندها بالضبط — دون الحاجة إلى إعادة الإعداد.

| الحقل | مطلوب | الوصف |
|---|---|---|
| `message` | لا | يتم عرضه للعميل على شاشة القفل الخاصة به. اتركه فارغاً لاستخدام النص الافتراضي. |
| `reason` | لا | ملاحظة داخلية للوكالة يتم تخزينها مع الإيقاف وفي سجل التدقيق — لا يتم عرضها للعميل أبداً. |

**cURL**

```bash
curl -X POST "https://api.dmchamp.com/v1/subaccounts/SUB_ACCOUNT_UID/pause" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "message": "Your account is on hold — contact us to reactivate it.", "reason": "Subscription suspended per client email" }'
```

**الاستجابة**

```json
{
  "success": true,
  "data": {
    "subAccountUid": "SUB_ACCOUNT_UID",
    "paused": true,
    "level": "hard_blocked"
  }
}
```

عندما يعود العميل، فإن `POST /v1/subaccounts/SUB_ACCOUNT_UID/unpause` (بدون نص) يزيل القفل — وتستأنف عمليات الإرسال وردود الذكاء الاصطناعي على الفور.

جدير بالمعرفة:

- **إنها نفس حالة مفتاح التبديل "محظور نهائياً" (Hard blocked) في لوحة التحكم** ([حظر / إيقاف حساب فرعي](sub-accounts.md#blocking-pausing-a-sub-account)) — العميل الذي يتم إيقافه عبر واجهة برمجة التطبيقات (API) يظهر كمحظور في لوحة التحكم والعكس صحيح، وإلغاء الإيقاف يزيل الحظر الموضوع من أي من الجانبين. يمكن قراءة الحالة الحالية من حقل `agency_block` في `GET /v1/subaccounts` (`level` من `"none"`، أو `"soft_blocked"` أو `"hard_blocked"`).
- **كلا الاستدعاءين متماثلان (idempotent).** إيقاف عميل متوقف بالفعل يقوم فقط بتحديث الرسالة والسبب والطابع الزمني؛ وإلغاء إيقاف عميل نشط لا يغير شيئاً.
- **لا يتم إرسال بريد إلكتروني للعميل تلقائياً** — العديد من الوكالات تستخدم علامتها التجارية الخاصة (white-label)، لذا فإن إبلاغ العميل متروك لك.
- **فواتير DM Champ الخاصة بك لا تتأثر.** إيقاف العميل يؤثر فقط على علاقتك به.
- **مساعدو الذكاء الاصطناعي يمكنهم القيام بذلك أيضاً**: يوفر [خادم MCP](../integrations/connect-ai-clients.md) هذه النقاط النهائية كأدوات `pause_subaccount` و `unpause_subaccount`.

***

## منح أو خصم الأرصدة مباشرة

`POST /v1/subaccounts/credits`

يضيف أو يزيل مبلغاً محدداً من الرصيد من رصيد حساب فرعي واحد — وهو المعادل البرمجي (API) لتعديل الرصيد اليدوي في لوحة التحكم. هذا تغيير لمرة واحدة في الرصيد، يختلف عن إعدادات `monthly_credits` و `roll_over_to_next_month` و `rollover_cap_months` و `rollover_expiry_days` المتكررة الموجودة في [`PUT /v1/subaccounts/{subAccountUid}/limits`](#set-an-exact-team-member-limit-for-a-client).

هذه هي نقطة النهاية الوحيدة في هذه الصفحة التي تحدد الحساب الفرعي عن طريق **البريد الإلكتروني** بدلاً من `sub_account_id`.

| الحقل | مطلوب | الوصف |
|---|---|---|
| `email` | نعم | البريد الإلكتروني للحساب الفرعي، كما هو موجود تحت وكالتك. |
| `amount` | نعم | عدد غير صفري من الأرصدة. القيمة الموجبة تضيف، والسالبة تخصم. |
| `description` | لا | يظهر بجانب التعديل في سجل رصيد العميل. الافتراضي هو سطر عام "تم التعديل بواسطة الوكالة عبر API". |

**cURL**

```bash
curl -X POST "https://api.dmchamp.com/v1/subaccounts/credits" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "email": "client@example.com", "amount": 500, "description": "Q3 bonus credits" }'
```

**الاستجابة**

```json
{
  "success": true,
  "data": {
    "email": "client@example.com",
    "previous_balance": 1200,
    "adjustment": 500,
    "new_balance": 1700
  }
}
```

يتم رفض أي `amount` سلبي من شأنه أن يجعل الرصيد أقل من الصفر مع `400`، مما يخبرك بالرصيد المتاح والمبلغ الذي حاولت خصمه. إذا كان العميل يستخدم نظام فوترة Stripe الخاص به (وضع إعادة البيع)، فإن المبلغ المضاف يُحتسب أيضاً كأرصدة قام بشرائها، لذا فهو يبقى بعد إعادة التعيين الشهرية التالية بنفس الطريقة التي يعمل بها الشحن الحقيقي؛ أما في حالة العميل المخصص القياسي، فيتم التعامل معه كجزء من مخصصاته المتكررة بدلاً من ذلك. في كلتا الحالتين، هي إضافة لمرة واحدة، لذا فإن حد الترحيل أو تاريخ انتهاء الصلاحية المحدد للحساب (أو خطته) لا يقلصها أبداً — فقط المخصصات المتكررة وأرصدة الخطة تخضع لتلك القيود.

***

## قراءة محادثات حساب فرعي

`GET /v1/subaccounts/{subAccountUid}/chats` · `GET /v1/subaccounts/{subAccountUid}/chats/{contactId}/messages`

تتيح لك إنشاء عرض مراقبة أو دعم لمحادثات العميل دون تسجيل الدخول إلى حسابه. ابدأ بسرد جهات الاتصال الخاصة به مع معاينة لأحدث رسالة، ثم اقرأ سجل الرسائل الكامل لجهة اتصال واحدة.

**سرد جهات الاتصال**

```bash
curl "https://api.dmchamp.com/v1/subaccounts/SUB_ACCOUNT_UID/chats?apiKey=YOUR_AGENCY_API_KEY&pageSize=25"
```

| معامل الاستعلام | مطلوب | الوصف |
|---|---|---|
| `pageSize` | لا | عدد جهات الاتصال في كل صفحة. القيمة الافتراضية 25، والحد الأقصى 50. |
| `lastActivityAt` | لا | مؤشر الترقيم — مرر `lastActivityAt` الخاص بالصفحة السابقة للمتابعة. |
| `searchQuery` | لا | التصفية حسب اسم جهة الاتصال أو رقم الهاتف. |

**الاستجابة**

```json
{
  "success": true,
  "data": {
    "contacts": [
      {
        "contactId": "contact456",
        "firstName": "Jamie",
        "lastName": "Lee",
        "phoneNumber": "+14155551234",
        "email": "jamie@example.com",
        "channel": "whatsapp",
        "lastActivityAt": "2026-08-30T14:22:00.000Z",
        "lastMessage": { "body": "Thanks, that fixed it!", "direction": "inbound", "timestamp": "2026-08-30T14:22:00.000Z" },
        "isBotActive": true,
        "markChatClosed": false
      }
    ],
    "subAccountName": "Client Co",
    "subAccountEmail": "client@example.com",
    "hasMore": true,
    "lastActivityAt": "2026-08-30T14:22:00.000Z"
  }
}
```

يتم ترتيب جهات الاتصال حسب النشاط الأحدث أولاً. استمر في الترقيم باستخدام `lastActivityAt` طالما أن `hasMore` هو `true`.

**قراءة رسائل جهة اتصال واحدة**

```bash
curl "https://api.dmchamp.com/v1/subaccounts/SUB_ACCOUNT_UID/chats/contact456/messages?apiKey=YOUR_AGENCY_API_KEY&pageSize=30"
```

| معامل الاستعلام | مطلوب | الوصف |
|---|---|---|
| `pageSize` | لا | عدد الرسائل في كل صفحة. القيمة الافتراضية 30، والحد الأقصى 100. |
| `beforeTimestamp` | لا | مؤشر الترقيم — اجلب الرسائل الأقدم من طابع ISO الزمني هذا. |

**الاستجابة**

```json
{
  "success": true,
  "data": {
    "messages": [
      {
        "messageId": "msg789",
        "body": "Thanks, that fixed it!",
        "direction": "inbound",
        "timestamp": "2026-08-30T14:22:00.000Z",
        "status": "received",
        "channel": "whatsapp",
        "botReply": false,
        "mediaUrl": null,
        "mediaContentType": null,
        "name": "Jamie Lee",
        "role": null
      }
    ],
    "contactInfo": { "firstName": "Jamie", "lastName": "Lee", "phoneNumber": "+14155551234", "channel": "whatsapp" },
    "hasMore": false,
    "oldestTimestamp": "2026-08-30T14:22:00.000Z"
  }
}
```

تظهر الرسائل من الأحدث إلى الأقدم؛ تصفح السجل للخلف باستخدام `beforeTimestamp`.

***

## قراءة استخدام الرصيد وحالة الحملة عبر محفظة عملائك

`GET /v1/subaccounts/credit-usage` · `GET /v1/subaccounts/campaign-status`

ملخصان بنمط لوحة التحكم لكل حساب فرعي تديره، وذلك لبناء تقارير الوكالة الخاصة بك بدلاً من النقر داخل كل عميل على حدة.

**استخدام الرصيد**

```bash
curl "https://api.dmchamp.com/v1/subaccounts/credit-usage?apiKey=YOUR_AGENCY_API_KEY&from=2026-08-01&to=2026-08-31"
```

| معامل الاستعلام | مطلوب | الوصف |
|---|---|---|
| `from` / `to` | نعم | نطاق تاريخ ISO. |
| `subAccountId` | لا | اتركه فارغاً للحصول على ملخص على مستوى الوكالة، صف واحد لكل حساب فرعي. قم بتضمينه للتبديل إلى وضع التفاصيل: ملخص ذلك الحساب الفرعي بالإضافة إلى سجلات الاستخدام الخام والمقسمة إلى صفحات. |
| `limitCount` | لا | وضع التفاصيل فقط. القيمة الافتراضية 500، والحد الأقصى 2000. |
| `startAfterTimestamp` | لا | وضع التفاصيل فقط — مؤشر الترقيم. |

```json
{
  "success": true,
  "data": {
    "subAccounts": [
      {
        "subAccountId": "abc123def456",
        "subAccountName": "Client Co",
        "subAccountEmail": "client@example.com",
        "totalCreditsUsed": 842,
        "totalCostUsd": 3.15,
        "byReason": { "AI reply": 620, "Chat summary": 80 },
        "topCampaigns": [{ "campaignName": "Inbound Leads", "creditsUsed": 500 }]
      }
    ],
    "totals": { "totalCreditsUsed": 842, "totalCostUsd": 3.15, "totalRecords": 214 },
    "dateRange": { "from": "2026-08-01", "to": "2026-08-31" },
    "hasMore": false,
    "lastTimestamp": null
  }
}
```

مرر `subAccountId` وستحمل الاستجابة نفسها أيضاً `records`: رسوم فردية مع `amount` و`reason` و`campaignName` و`contactName` و`timestamp`. العميل الذي ينفق باستخدام مفتاح BYOK الخاص به بدلاً من أرصدتك يتم حجب أرقام التكلفة/الرموز عنه (`costsRedacted: true`) — فهذه بيانات قياس تكلفة المنصة، وليست شيئاً يجب إظهاره لمشاهد إعادة البيع.

**حالة الحملة**

```bash
curl "https://api.dmchamp.com/v1/subaccounts/campaign-status?apiKey=YOUR_AGENCY_API_KEY&pageSize=20"
```

| معلمة الاستعلام | مطلوبة | الوصف |
|---|---|---|
| `pageSize` | لا | عدد الحسابات الفرعية في كل صفحة. القيمة الافتراضية 10، والحد الأقصى 50. |
| `lastDocumentId` | لا | مؤشر الترقيم (Pagination cursor). |
| `searchQuery` | لا | التصفية حسب اسم الحساب الفرعي أو البريد الإلكتروني. |

```json
{
  "success": true,
  "data": {
    "totalSubAccounts": 34,
    "subAccountsWithIssues": 3,
    "totalLiveCampaigns": 51,
    "totalPausedCampaigns": 6,
    "subAccounts": [
      {
        "userId": "abc123def456",
        "email": "client@example.com",
        "displayName": "Jamie Lee",
        "businessName": "Client Co",
        "totalCampaigns": 2,
        "liveCampaigns": 1,
        "pausedCampaigns": 1,
        "hasIssues": true,
        "issueDetails": ["1 campaign paused"],
        "lastCampaignActivity": "2026-08-29T09:00:00.000Z"
      }
    ],
    "hasMore": true,
    "lastDocumentId": "abc123def456",
    "pageSize": 20
  }
}
```

تُستخدم العلامة `hasIssues` / `issueDetails` لتحديد الحسابات الفرعية التي تستحق المراجعة — مثل حملة متوقفة مؤقتاً، أو حملة لم يتم توجيه أي قناة إليها، على سبيل المثال. استخدم هذا لبناء لوحة تحكم لفحص الحالة عبر كامل قائمة عملائك بدلاً من فتح حساب كل عميل لاكتشاف الحملات المتوقفة.

> للحصول على بيانات المراسلات ونشاط الرصيد عبر جميع العملاء (سلسلة زمنية جاهزة للرسم البياني بدلاً من لقطة في لحظة زمنية معينة)، راجع `GET /analytics/agency-rollup` في دليل واجهة برمجة تطبيقات التحليلات (Analytics API).

***

## شحن حساب عميل تم إعداده مسبقاً

`PUT /v1/snapshots/default` · `POST /v1/snapshots/{snapshotId}/apply`

تُعد [اللقطة](snapshots.md) (snapshot) قالباً قابلاً لإعادة الاستخدام: وكيل ذكاء اصطناعي واحد أو أكثر بالإضافة إلى قاعدة معارفهم وأدواتهم ووسائطهم، يتم التقاطها من حسابك الخاص. هناك نقطتا نهاية تضعانها في تدفق التزويد الخاص بك.

**تلقائي — كل عميل جديد يحصل عليها فور إنشائه.** قم بتمييز لقطة كنقطة افتراضية مرة واحدة، وسيصل كل حساب تنشئه بعد ذلك وهي مثبتة فيه. يغطي هذا الحسابات التي يتم إنشاؤها من خلال `POST /v1/subaccounts`، والحسابات التي تنشئها في لوحة التحكم، والحسابات التي يتم إنشاؤها تلقائياً عندما يدفع العميل من خلال رابط الدفع الخاص بك.

أولاً، ابحث عن معرف اللقطة:

```bash
curl "https://api.dmchamp.com/v1/snapshots" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY"
```

ثم قم بتعيينها كافتراضية:

```bash
curl -X PUT "https://api.dmchamp.com/v1/snapshots/default" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "snapshot_id": "SNAPSHOT_ID" }'
```

هذا هو كل ما يتطلبه التكامل. أرسل `{"snapshot_id": null}` لإيقاف تشغيلها مرة أخرى. يمكنك القيام بنفس الشيء من لوحة التحكم بالنقر على النجمة في صفحة **اللقطات** (Snapshots).

لقراءة ما تم تمييزه بنجمة حالياً (على سبيل المثال، قبل أن يقرر برنامج التزويد ما إذا كان سيقوم بتعيين واحد)، تُرجع `GET /v1/snapshots/default` القيمة `{ "success": true, "data": { "default_snapshot_id": "SNAPSHOT_ID" } }` — أو `null` عندما لا يكون هناك شيء مميز بنجمة. تُرجع `GET /v1/snapshots` (المستخدمة للعثور على المعرف أعلاه) نفس `default_snapshot_id` إلى جانب مصفوفة `snapshots` الكاملة، لذا فإن معظم عمليات التكامل تحتاج فقط إلى هذا الاستدعاء. توجد حقول كائن اللقطة (Snapshot) الكاملة في دليل [اللقطات](snapshots.md).

**عند الطلب — التثبيت في حساب واحد.** مفيد لتهيئة عميل حالي، أو لمنح عميل قالباً ثانياً لاحقاً.

```bash
curl -X POST "https://api.dmchamp.com/v1/snapshots/SNAPSHOT_ID/apply" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "sub_account_id": "SUB_ACCOUNT_UID" }'
```

احذف `sub_account_id` وسيتم تثبيتها في حساب الوكالة الخاص بك بدلاً من ذلك. مثل نقاط نهاية `/subaccounts`، تقوم هذه بتسمية الحساب المستهدف في المسار أو النص بدلاً من استخدام معامل `sub_account_id` العام.

أشياء تستحق المعرفة قبل البناء عليها:

- **الوكلاء المثبتون يبدأون في حالة إيقاف مؤقت.** قم بتوصيل قنوات العميل أولاً، ثم قم بتنشيط الوكيل. هذا ينطبق على كل من المسار التلقائي والمسار عند الطلب.
- **التزويد لا يفشل أبداً بسبب لقطة.** إذا تعذر إكمال التثبيت، فسيتم إنشاء حساب العميل ويظل قابلاً للاستخدام - سيصل فارغاً فقط ويمكنك تطبيق اللقطة لاحقاً.
- **لا يتم نسخ القنوات والتقويمات واتصالات OAuth أبداً.** يقوم كل حساب بتوصيل اتصالاته الخاصة. الأدوات التي تستخدم مفتاح API بسيط تستمر في العمل فوراً.
- **التطبيق مرتين ينشئ نسخة ثانية.** لا يتم استبدال أي شيء.

***

## إنشاء القالب نفسه عبر واجهة برمجة التطبيقات (API)

`POST /v1/snapshots` · الوكلاء، والوظائف المخصصة، والوسائط عبر واجهة برمجة التطبيقات (API)

يوزع القسم أعلاه لقطة (snapshot) أنشأها شخص ما في لوحة التحكم. كما أن جانب التأليف متاح أيضاً، بحيث يمكن تشغيل الحلقة بأكملها — تجميع الإعداد الرئيسي مرة واحدة، والتقاطه، وتسليمه لكل عميل — من خلال الكود.

الأجزاء، بالترتيب الذي يستخدمها به برنامج التزويد:

1. **أنشئ وظائفك المخصصة.** تقوم `POST /v1/custom-functions` بإنشاء واحدة؛ وتسرد `GET /v1/custom-functions` ما لديك، وتقوم `GET` و `PUT` و `DELETE` على `/v1/custom-functions/{customFunctionId}` بقراءة وتحديث وإزالة واحدة. تقوم `POST /v1/custom-functions/test` بتشغيل تجريبي للتعريف قبل حفظه.
2. **أنشئ الوكيل وقم بتشكيله.** تقوم `POST /v1/agents` بإنشائه، وتقوم `PUT /v1/agents/{agentId}` بتحديثه، وتقوم `PATCH /v1/agents/{agentId}/active` مع `{ "active": false }` بإبقائه متوقفاً مؤقتاً أثناء عملك (نفس الاستدعاء مع `true` يجعله مباشراً). تسرد `GET /v1/agents` هذه الوكلاء.
3. **امنح الوكيل قدراته.** تقوم `POST /v1/agents/{agentId}/custom-functions` مع `{ "custom_function_id": "..." }` بإرفاق وظيفة بالوكيل؛ وتقوم `DELETE /v1/agents/{agentId}/custom-functions/{customFunctionId}` المطابقة بإلغاء إرفاقها.
4. **املأ مكتبة الوسائط.** تقوم `POST /v1/agents/{agentId}/media-library` بتحميل عنصر (JSON مع `base64Data` و `mimeType` و `title` و `description`)؛ وتسرد `GET` عناصر الوكيل، وتقوم `PATCH`/`DELETE` على `/{itemId}` بتحديث أو إزالة أحدها.
5. **التقطه كلقطة (snapshot).**

```bash
curl -X POST "https://api.dmchamp.com/v1/snapshots" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Master setup v1",
    "agent_ids": ["AGENT_ID"],
    "include_knowledge": true,
    "include_tools": true,
    "include_media": true
  }'
```

من هناك، نعود إلى القسم السابق: قم بتمييزه كافتراضي بحيث يولد كل عميل جديد به، أو قم بتطبيقه عند الطلب. توجد أدوات التنظيم جنباً إلى جنب: تقوم `PATCH /v1/snapshots/{snapshotId}` مع `{ "name": "..." }` بإعادة تسمية واحدة، وتقوم `DELETE /v1/snapshots/{snapshotId}` بحذف واحدة (وإلغاء تمييزها إذا كانت هي الافتراضية)، وتسرد `GET /v1/snapshots/apply-targets` كل حساب يمكنك التثبيت فيه.

تقبل جميع نقاط نهاية الوكيل والوظائف المخصصة والوسائط `sub_account_id`، لذا يمكن لنفس الاستدعاءات أيضاً صيانة وكيل مباشرة داخل حساب عميل واحد. تعمل استدعاءات اللقطات (Snapshot) دائماً على حساب وكالتك — حيث يعيش القالب معك. توجد مخططات الطلب والاستجابة الكاملة لكل هذه العناصر في [مرجع واجهة برمجة التطبيقات](../api/reference.md).

***

## إدارة مستويات التسعير الخاصة بك عبر API

`GET /v1/agency/pricing-tiers` · `POST /v1/agency/pricing-tiers` · `PATCH /v1/agency/pricing-tiers/{tierIndex}` · `DELETE /v1/agency/pricing-tiers/{tierIndex}`

يمكن قراءة وتغيير الخطط التي تبيعها في **وضع SaaS ← مستويات التسعير** من خلال الكود، بحيث يمكن للوحة تحكم المسؤول الخاصة بك أو برنامج التزويد إضافة خطة، أو تعديل سعر، أو تقديم رابط دفع دون أن يضطر أي شخص لفتح لوحة التحكم. قم بالمصادقة باستخدام مفتاح API الخاص بوكالتك مثل أي استدعاء آخر في هذه الصفحة؛ نقاط النهاية هذه على مستوى الوكالة، لذا فهي لا تأخذ `sub_account_id`. كل عملية كتابة تقوم بتشغيل نفس التحقق ونفس مزامنة منتج وسعر Stripe مثل حفظ لوحة التحكم، لذا فإن الخطة التي يتم إنشاؤها هنا لا يمكن تمييزها عن تلك التي قمت بإعدادها يدويًا.

### سرد مستوياتك

```bash
curl "https://api.dmchamp.com/v1/agency/pricing-tiers" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY"
```

**الاستجابة**

```json
{
  "success": true,
  "data": {
    "tiers": [
      {
        "tierIndex": 0,
        "credits": 1000,
        "price_cents": 2900,
        "currency": "usd",
        "label": "Starter",
        "billing_interval": "month",
        "trial_days": 14,
        "trial_credits": 250,
        "trial_card_required": false,
        "trial_hard_expiry": true,
        "stripe_price_id": "price_1PxAbC…",
        "stripe_product_id": "prod_QxAbC…",
        "checkout_url": "https://app.yourdomain.com/v1/checkout?id=YOUR_AGENCY_UID&tierIndex=0"
      }
    ],
    "count": 1,
    "max_tiers": 20
  }
}
```

يتم إرجاع كل مستوى مع **`tierIndex`** الخاص به — موقعه في قائمة الخطط الخاصة بك، وهو ما تشير إليه المكالمات الثلاث الأخرى — و **`checkout_url`** جاهز للمشاركة، وهو نفس الرابط الذي تمنحه علامة التبويب **المدفوعات**، والذي يشير بالفعل إلى [نطاق العلامة البيضاء](white-labeling.md) الذي تُباع عليه تلك الخطة.

### إضافة مستوى

الجسم عبارة عن كائن مستوى واحد؛ يتم إلحاقه بنهاية قائمتك.

```bash
curl -X POST "https://api.dmchamp.com/v1/agency/pricing-tiers" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "Starter",
    "credits": 1000,
    "price_cents": 2900,
    "currency": "usd",
    "billing_interval": "month",
    "trial_days": 14,
    "trial_credits": 250,
    "trial_card_required": false,
    "trial_hard_expiry": true,
    "features": ["channels_3", "channel_whatsapp_web", "webhooks"]
  }'
```

تحمل الاستجابة المستوى الذي تم إنشاؤه، بما في ذلك `tierIndex` الذي استقر عليه و `checkout_url` الخاص به.

### تحرير مستوى

أرسل فقط الحقول التي تريد تغييرها؛ يتم ترك كل شيء آخر في الخطة كما كان.

```bash
curl -X PATCH "https://api.dmchamp.com/v1/agency/pricing-tiers/0" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "price_cents": 3900, "trial_hard_expiry": true }'
```

يتم رفض الحقل الذي لا تتعرف عليه واجهة برمجة التطبيقات بدلاً من تجاهله، ويقوم الخطأ بتسميته — لذا لا يمكن لخطأ مطبعي أبدًا كتابة إعداد يبدو مباشرًا ولكنه لا يفعل شيئًا بهدوء. يؤدي تغيير السعر أو الأرصدة أو العملة أو وتيرة الفوترة إلى إنشاء سعر جديد في Stripe الخاص بك؛ يظل العملاء الذين اشتركوا بالفعل على ما اشتركوا فيه.

### حذف مستوى

```bash
curl -X DELETE "https://api.dmchamp.com/v1/agency/pricing-tiers/2" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY"
```

نفس قاعدة لوحة التحكم: لا يمكن حذف خطة لا تزال تحتوي على مشتركين نشطين. يتم رفض الطلب، ويخبرك بعدد المشتركين الموجودين عليه — قم بإلغائهم أو ترحيلهم أولاً. يستجيب الحذف الناجح بمستوياتك المتبقية، والتي تمت إعادة ترقيمها بالفعل.

### الحقول الموجودة في المستوى

| الحقل | ما هو |
|---|---|
| `label` / `description` | اسم الخطة، والسطر الاختياري الذي يظهر في صفحة الدفع الخاصة بك. |
| `credits` | الأرصدة التي يحصل عليها العميل **شهرياً** في الخطة الشهرية أو السنوية، و**لكل فترة فوترة** في الخطة الأسبوعية. |
| `price_cents` | السعر لكل فترة فوترة، بأصغر وحدة عملة (`2900` = 29.00 دولاراً). في الخطة السنوية، هذا هو سعر السنة بأكملها. |
| `currency` | رمز ISO بأحرف صغيرة — `usd`، `eur`، `gbp` وما إلى ذلك. |
| `billing_interval` / `billing_interval_count` | `month` (الافتراضي)، `year`، أو `week` مع عدد من 1–52 لـ "كل N أسبوع". |
| `trial_days` | مدة الفترة التجريبية المجانية، من 0 إلى 90. `0` (أو تركها فارغة) يعني عدم وجود فترة تجريبية. |
| `trial_credits` | الأرصدة التي يبدأ بها العميل الفترة التجريبية. يتم تعيينها افتراضياً على `credits` الخاصة بالخطة. |
| `trial_card_required` | يسمح `false` للعميل ببدء الفترة التجريبية دون إدخال بطاقة. يتم تعيينه افتراضياً على `true`. |
| `trial_hard_expiry` | يقوم `true` بإعادة أرصدة الفترة التجريبية غير المستخدمة إلى مجمعك وقفل حساب العميل عند انتهاء الفترة التجريبية دون ترقية. يتم تعيينه افتراضياً على `false` — انظر [انتهاء الصلاحية الصارم بعد الفترة التجريبية](agency-accounts.md#step-3--set-up-pricing-tiers). |
| `rollover_cap_months` | أشهر المخصصات التي يمكن للعملاء في هذه الخطة ترحيلها بين التجديدات — رقم من 0 إلى 120، الكسور مسموح بها. `0` لا يرحل شيئاً؛ `null` (الافتراضي) يعني عدم وجود حد أقصى. انظر [تحديد ما يتم ترحيله](sub-accounts.md#capping-what-rolls-over). |
| `rollover_expiry_days` | الأيام التي يتم بعدها إسقاط الأرصدة غير المستخدمة عند التجديد التالي — رقم صحيح من 1 إلى 3650. `null` (الافتراضي) يعني أنها لا تنتهي صلاحيتها أبداً. |
| `features` / `feature_settings` | ما يحصل عليه العملاء في هذه الخطة — نفس معرفات الميزات الموجودة في [اختر أنواع القنوات التي يمكن للعميل الاتصال بها](#choose-which-channel-types-a-client-can-connect). |
| `team_seats_limit` | مقاعد الفريق التي تمنحها الخطة: رقم محدد، `0` لعدم وجود مقاعد، `-1` لعدد غير محدود. |
| `white_label_config` | أي من [نطاقات العلامة البيضاء](white-labeling.md#up-to-three-white-labels) الخاصة بك يتم بيع الخطة عليها. |

حقول الفترة التجريبية لا تعني شيئاً إلا في الخطة التي تحتوي على فترة تجريبية: احفظ مستوى بـ `trial_days: 0` وسيتم إسقاطها. تتم إدارة معرفات منتج وسعر Stripe الخاصة بالخطة نيابة عنك ولا يمكن تعيينها يدوياً.

ثلاثة أمور يجب مراعاتها:

- **فهارس المستويات هي مواضع وليست معرفات دائمة.** يؤدي حذف خطة إلى إزاحة كل خطة تليها بمقدار موضع واحد، لذا أعد جلب القائمة بعد أي تغيير — وأعد نسخ روابط الدفع التي نشرتها، تماماً كما تفعل بعد حذف خطة في لوحة التحكم.
- **يجب إعداد وضع SaaS أولاً.** تتطلب نقاط النهاية هذه حساب وكالة مع ميزة العلامة البيضاء (white labeling) ومفتاح Stripe محفوظ مسبقاً؛ فبدون ذلك، لن يكون هناك حساب Stripe ليعيش عليه منتج الخطة وسعرها.
- **الحد الأقصى هو عشرون خطة**، وهو نفس الحد الموجود في لوحة التحكم. يخبرك الحقل `max_tiers` في استجابة القائمة بالحد الحالي.

توجد مخططات الطلب والاستجابة الكاملة في [مرجع API](../api/reference.md)، تحت قسم **الوكالة (Agency)**.

***

## تعيين سعر الرصيد الخاص بك عبر واجهة برمجة التطبيقات (API)

`GET /v1/agency/credit-price` · `PATCH /v1/agency/credit-price`

يمكن قراءة وتغيير السعر الذي يدفعه العملاء مقابل عمليات الشحن المخصصة (**وضع SaaS ← تسعير الرصيد**) من خلال الكود أيضاً. تم تصميم هذه الميزة للحالات التي يتطلب فيها السعر التغيير تلقائياً: فمثلاً، يمكن لوكالة تبيع الأرصدة بعملة ما ولكنها تحاسب بعملة أخرى استخدام مهمة مجدولة لتعديل السعر مع تغير سعر الصرف، بدلاً من قيام شخص ما بتعديله يدوياً كل أسبوع.

### قراءة السعر الحالي

```bash
curl "https://api.dmchamp.com/v1/agency/credit-price" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY"
```

**الاستجابة**

```json
{
  "success": true,
  "data": {
    "price_per_credit_cents": 125,
    "price_per_credit_currency": "brl",
    "note": "USD 0.25 per credit at our reference rate",
    "minimum_cents": 60
  }
}
```

`minimum_cents` هو أقل سعر تسمح به المنصة بتلك العملة، لذا يمكن للمهمة التحقق من السعر الجديد قبل إرساله. تكون القيم الثلاث جميعها `null` حتى يتم تعيين سعر.

### تغييره

```bash
curl -X PATCH "https://api.dmchamp.com/v1/agency/credit-price" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "price_per_credit_cents": 130, "currency": "brl" }'
```

أرسل فقط ما تريد تغييره. `price_per_credit_cents` هو السعر بأصغر وحدة عملة (`130` = 1.30 ريال برازيلي)؛ `currency` هو رمز ISO بأحرف صغيرة؛ `note` هو سطر اختياري يصل إلى 200 حرف يظهر للعملاء مباشرة تحت سعر الرصيد في صفحة الفواتير الخاصة بهم — وهو مفيد للإشارة إلى سعر مرجعي بعملة أخرى، مثل *"0.25 دولار أمريكي لكل رصيد بسعرنا المرجعي"*. أرسل `"note": ""` لإزالته. الاستجابة لها نفس شكل القراءة أعلاه، لذا يمكن للمهمة المقارنة وتخطي الكتابة عندما لا يتغير شيء.

تطبق نفس القواعد الموجودة في لوحة التحكم: لا يمكن أن يقل السعر عن الحد الأدنى للمنصة لتلك العملة، ويحتاج الحساب إلى ميزة العلامة البيضاء (white labeling). على عكس نقاط نهاية مستويات التسعير، لا يلزم وجود مفتاح Stripe لقراءة هذه القيمة أو تغييرها.

### امنح المهمة مفتاحاً لا يمكنه القيام بأي شيء آخر

إن وضع مفتاح الوكالة الكامل الخاص بك في مجدول مهام يمنح صلاحيات وصول أكثر مما يحتاجه تحديث السعر. بدلاً من ذلك، قم بإنشاء **مفتاح محدد النطاق (scoped key)** مقتصر على منطقة **سعر رصيد الوكالة (Agency Credit Price)**: يمكن لهذا المفتاح قراءة وتغيير السعر لكل رصيد ولا شيء غير ذلك — فهو لا يمكنه الوصول إلى الحسابات الفرعية، أو الخطط، أو الأرصدة، أو اتصال Stripe الخاص بك.

```bash
curl -X POST "https://api.dmchamp.com/v1/api-keys" \
  -H "X-API-Key: YOUR_AGENCY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "label": "FX price updater", "scopes": { "read_only": false, "tags": ["Agency Credit Price"] } }'
```

تحمل الاستجابة المفتاح الجديد في `api_key` **مرة واحدة فقط** — ولن يتم عرضه مرة أخرى، لذا قم بحفظه على الفور. قم بتعيين `"read_only": true` للمفتاح الذي يحتاج فقط إلى قراءة السعر، وأضف `"expires_at"` (تاريخ بتنسيق ISO) إذا كنت تريده أن يتوقف عن العمل تلقائياً. يمكن لمالك الحساب فقط إنشاء مفاتيح محددة النطاق؛ يمكنك سردها أو إلغاؤها باستخدام `GET /v1/api-keys` و `DELETE /v1/api-keys/{id}`.

***

## السماح لحساب فرعي بقراءة أسعارك

`GET /v1/subaccounts/agency-pricing`

يتم استدعاء كل نقطة نهاية أخرى في هذه الصفحة باستخدام **مفتاح الوكالة الخاص بك**، مع استهداف عميل اختياريًا عبر `sub_account_id`. هذه النقطة هي العكس تمامًا: يتم استدعاؤها باستخدام **مفتاح API الخاص بالحساب الفرعي**، بدون `sub_account_id`، بحيث يمكن لصفحة تعبئة الرصيد الخاصة بالعميل (أو التكامل الذي تبنيه له) عرض ما تفرضه عليهم دون رؤية حساب الوكالة الخاص بك مطلقًا.

```bash
curl "https://api.dmchamp.com/v1/subaccounts/agency-pricing" \
  -H "X-API-Key: THE_SUB_ACCOUNTS_OWN_API_KEY"
```

**الاستجابة**

```json
{
  "success": true,
  "data": {
    "tiers": [{ "credits": 1000, "price_cents": 2900, "currency": "usd" }],
    "price_per_credit_cents": 125,
    "price_per_credit_currency": "brl",
    "price_per_credit_note": "USD 0.25 per credit at our reference rate",
    "agency_display_name": "Client Co's Growth Partner"
  }
}
```

يعكس هذا تماماً ما تُرجعه [`GET /v1/agency/pricing-tiers`](#list-your-tiers) و [`GET /v1/agency/credit-price`](#read-the-current-price) لك كوكالة، مطروحاً منه أي شيء لا يحتاج العميل إلى رؤيته (معرفات Stripe، و `max_tiers`، وما إلى ذلك). يعمل هذا فقط مع حساب هو في الواقع حساب فرعي مرتبط بوكالة — استدعاؤه من حساب وكالتك الخاص يُرجع خطأ في الصلاحيات.

***

## أمور يجب وضعها في الاعتبار

- **استخدم مفتاح الوكالة الخاص بك.** قم بمصادقة كل استدعاء باستخدام مفتاح API الخاص بحساب الوكالة - وليس الحساب الفرعي. المعلمة `sub_account_id` هي التي توجه الإجراء.
- **تُخصم الأرصدة من الحساب الفرعي.** تؤثر عمليات الشراء والرسوم المتكررة على رصيد الحساب الفرعي المستهدف، وليس رصيدك.
- **يعني الرمز `404` "ليس حسابك الفرعي".** تحقق جيداً من المعرف ومن أن الحساب هو أحد الحسابات التي تديرها.
- **المعلمة اختيارية في كل مكان تُقبل فيه.** إذا حذفتها، سيعمل نفس نقطة النهاية على حساب الوكالة الخاص بك، مما يتيح لك إعادة استخدام تكامل واحد لكليهما.

***

## ذات صلة

- [الوصول إلى واجهة برمجة التطبيقات](../integrations/api-access.md) — المصادقة، عنوان URL الأساسي، الأخطاء، حدود المعدل.
- [الحسابات الفرعية](sub-accounts.md) — سرد وإدارة الحسابات التي يمكنك استهدافها.
- [إعادة الشحن التلقائي للحساب الفرعي](sub-account-auto-recharge.md) — منح رصيد لحساب فرعي عبر خطاف الويب (webhook) + واجهة برمجة التطبيقات.
- [واجهة برمجة تطبيقات الحملات](../api/campaigns.md) — إنشاء وتحديث ونسخ الحملات، بما في ذلك مرجع الحقول الكامل.
- [واجهة برمجة تطبيقات اتصال القنوات](../api/channels.md) — توصيل قنوات العميل وتوجيهها إلى حملة.
- دليل واجهة برمجة تطبيقات التحليلات (في قسم واجهة برمجة التطبيقات) — تجميع الحسابات الفرعية للوكالة وجميع نقاط نهاية التقارير الأخرى.
- [اللقطات](snapshots.md) — ما تلتقطه اللقطة وكيفية إنشائها في لوحة التحكم.
