WidersApps WidersApps

واجهة WidersApps البرمجية

واجهة REST لبيانات WidersApps — جهات الاتصال والمحادثات والطلبات والحجوزات. JSON دخولاً وخروجاً، بغلاف موحّد واحد، ومؤمّنة بمفتاح Bearer تنشئه بنفسك.

العنوان الأساسي

كل نقطة نهاية تقع تحت مسار أساسي واحد يحمل رقم الإصدار. أرسِل كل الطلبات عبر HTTPS.

https://console.widers.net/api/v1

الموارد

الموارد الأساسية والصلاحية التي تحتاجها كل قدرة. هذه مجموعة مختارة للبدء — والمرجع التفاعلي يسرد كل نقطة نهاية تكشفها الواجهة، بتفاصيل الطلب والاستجابة لكلٍّ منها.

الموردما يمكنك فعلهالنطاق
جهات الاتصالعرض القائمة · عرض واحد · إنشاء · تعديل · حذفcontacts.view · contacts.manage
المنتجاتعرض القائمة · عرض واحد · إنشاء وتحديث الحقول الأساسية (الاسم، السعر، الحالة، المخزون — لمزامنة الكتالوج والمخزون)commerce.view · commerce.manage
الطلباتعرض القائمة · عرض واحد · إنشاء · تقديم الحالةcommerce.view · commerce.manage
الرسائلعرض القائمة · عرض واحد · إرسالinbox.access
المحادثاتعرض القائمة · عرض واحد · إسناد · تحويل · إغلاق · إعادة فتح · تعليم مقروء · كتم · أرشفة · متابعة · ملاحظة · وسمinbox.access
الحجوزاتCRUD كامل + الأوقات المتاحةcalendar.view · calendar.manage
الوسومعرض الوسوم؛ وإنشاء/إعادة تسمية/حذف وسومك (وسوم النظام للقراءة فقط)inbox.access · tags.manage
الوسائطرفع ملف والحصول على رابط لإرفاقه عند إرسال رسالةinbox.access
الردود السريعةعرض وإنشاء الردود السريعة المحفوظةquick-replies.manage
الحملاتعرض الحملات وإحصاءاتها؛ وإيقاف/استئناف/إلغاء حملة جاريةcampaigns.view · campaigns.manage
إنشاء الطلب يرفعه دائماً بحالة «قيد الانتظار» — لا تُقبل أي حالة عند الإنشاء، فلا يُحتسب دخل بلا دفع. تقديم الطلب إلى حالة مدفوعة يختم paid_at دون تحصيل أي مبلغ (لمسارات الدفع اليدوي أو التحويل البنكي أو الدفع عند الاستلام) ويتطلّب صلاحية commerce.manage.

حالات تسليم الرسائل وقراءتها وفشلها تصل عبر الويب هوك (message.delivered · message.read · message.failed) لا كنقاط نهاية تُستعلَم. وتغيّرات دورة حياة المحادثة (إنشاء · إسناد · إغلاق · وسم · …) ويب هوك أيضاً — اشترك فيها من الإعدادات ← الويب هوك.

إنشاء مفتاح API

أنشئ مفتاحاً من لوحة التحكّم عبر: الإعدادات ← المطوّرون ← مفاتيح API (للمالك فقط). عند الإنشاء تختار:

  • اسماً — لتتعرّف عليه وتُبطله لاحقاً.
  • النطاقات — لا يمكنك منح إلا النطاقات التي تملكها أنت.
  • مباشر أم اختبار — مفتاح الاختبار (Sandbox) لا يمسّ بيانات حقيقية أبداً.
  • تاريخ انتهاء اختياري.

يُعرض المفتاح كاملاً مرّة واحدة عند الإنشاء. انسخه حينها واحفظه بأمان — وإن فقدته فأبطِله وأنشئ غيره.

المصادقة

صادِق كل طلب بمفتاح Bearer في ترويسة Authorization. الصق المفتاح تماماً كما عُرض لك، ببادئته:

Authorization: Bearer wa_live_<id>|<token>

مفتاح الاختبار يحمل البادئة wa_test_ بدلاً من ذلك:

Authorization: Bearer wa_test_<id>|<token>
البادئة wa_live_ / wa_test_ شكليّة فقط — تُزال قبل تحليل المفتاح. الوضع المباشر مقابل الاختبار يُفرَض بصلاحية المفتاح، لا بالبادئة، فتغيير البادئة لا يغيّر ما يقدر عليه المفتاح.

كل مستخدم ينتمي لشركة واحدة فقط، فالمفتاح يحدّد الحساب الذي يعمل عليه — لا وسيط للمستأجر تمرّره.

النطاقات (Scopes)

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

النطاقالوصف
contacts.view قراءة جهات الاتصال
contacts.manage إدارة جهات الاتصال
inbox.access الرسائل (قراءة وإرسال)
tags.manage إدارة الوسوم
quick-replies.manage إدارة الردود السريعة
commerce.view قراءة الطلبات والمنتجات
commerce.manage إدارة الطلبات والمنتجات
campaigns.view قراءة الحملات
campaigns.manage التحكم بالحملات (إيقاف مؤقت، استئناف، إلغاء)
calendar.view قراءة الحجوزات
calendar.manage إدارة الحجوزات

يُصدَر المفتاح بالنطاقات التي تحدّدها بالضبط — بلا تعميم، وبما لا يتجاوز ما تملكه أنت.

غلاف الاستجابة

الاستجابة الناجحة تغلّف البيانات داخل مفتاح data، مع كتلة meta اختيارية (تستخدمها القوائم المصفّحة):

{
  "data": { ... },
  "meta": { "next_cursor": null, "has_more": false }
}

يُرجِع الفشل كائن خطأ موحّداً واحداً:

{
  "error": {
    "type": "invalid_request_error",
    "code": "not_found",
    "message": "The requested resource was not found.",
    "param": null,
    "request_id": "req_01J..."
  }
}

رموز الأخطاء

سلسلة code عقد ثابت مقروء آلياً (مستقلّ عن اللغة، لا يُعاد تسميته) لتفرّع منطقك عليه؛ أمّا الرسالة البشرية message فتُترجَم على حدة. أمّا type فهو عائلة الخطأ العامّة.

الرمزالنوعHTTP
bad_request invalid_request_error 400
validation_failed invalid_request_error 422
unauthenticated authentication_error 401
forbidden authorization_error 403
not_found invalid_request_error 404
method_not_allowed invalid_request_error 405
not_acceptable invalid_request_error 406
conflict idempotency_error 409
idempotency_conflict idempotency_error 409
payload_too_large invalid_request_error 413
rate_limited rate_limit_error 429
server_error api_error 500

كل خطأ يردّد request_id (نفس قيمة ترويسة X-Request-Id) — اذكره عند الإبلاغ عن مشكلة.

حدود المعدّل

تسمح الواجهة بـ120 طلباً في الدقيقة لكل مفتاح (الطلبات غير المصادَقة تُحدّ بعنوان IP). كل استجابة تحمل الترويسات القياسية:

  • X-RateLimit-Limit, X-RateLimit-Remaining, Retry-After
  • تجاوز الحدّ يُرجِع 429 برمز rate_limited؛ تمهّل حتى Retry-After.

عدم التكرار (Idempotency)

أرسِل ترويسة Idempotency-Key مع أي POST أو PUT أو PATCH أو DELETE ليُطبَّق الطلب المُعاد مرّة واحدة على الأكثر. استخدم UUID جديداً لكل عملية منطقية:

Idempotency-Key: 6f9e0b2c-1a3d-4e5f-8a7b-9c0d1e2f3a4b
  • إعادة نفس المفتاح والجسم تُرجِع الاستجابة المخزّنة مع Idempotency-Replayed: true.
  • تُحفظ المفاتيح لمدّة 24 ساعة.
  • إعادة استخدام مفتاح بجسم مختلف، أو والطلب الأول ما زال جارياً، تُرجِع 409 idempotency_conflict.

التصفّح (Pagination)

القوائم تستخدم تصفّحاً مبهماً قائماً على المؤشّر (keyset). مرّر limit (افتراضياً 25، وأقصاه 100) ومؤشّراً cursor مبهماً:

GET https://console.widers.net/api/v1/contacts?limit=25&cursor=<opaque>

تحمل meta في الاستجابة مؤشّر الصفحة التالية وما إن كانت هناك صفوف أخرى. عندما يكون has_more قيمته false يكون next_cursor فارغاً null:

"meta": { "next_cursor": "eyJ...", "has_more": true }

المؤشّر التالف يُرجِع 422 — لا مسحاً كاملاً صامتاً. عامِل المؤشّر ككتلة مبهمة وأعده كما هو حرفياً.

وضع الاختبار (Sandbox)

وضع الاختبار يحمله المفتاح (مفتاح اختبار)، فلا تقلبه أثناء الطلب. طلب الـSandbox لا يمسّ عملاء أو طلبات أو أموالاً حقيقية — بل يصطنع الاستجابات:

  • كل استجابة تُعلن وضعها: X-Widers-Mode: live / X-Widers-Mode: test
  • مفتاح وضع الاختبار يتوقّف قبل أي أثر فعلي، فلا يُطلق أي Webhook — كل Webhook يصلك يكون من نشاط حقيقي.
  • الخدمات ذات الأثر الجانبي تصطنع نداءاتها الخارجية في وضع الاختبار.

توقيع الـWebhook

كل webhook نرسله إلى نقطتك موقّع بـHMAC مختوم بالوقت في ترويسة X-Widers-Signature، لتتحقّق من الأصالة والحداثة معاً:

X-Widers-Signature: t=1706342400,v1=<hmac_sha256>
  • تحقّق مقابل جسم الطلب الخام غير المحلَّل — احسب hmac_sha256(secret, "<t>.<body>").
  • ارفض أي طلب تبعد طابعه الزمني أكثر من 300 ثانية عن الآن (دفاعاً عن إعادة التشغيل).
  • قارِن بدالّة ثابتة الزمن (hash_equals) تفادياً لهجمات التوقيت.

مُتحقّق جاهز للنسخ (PHP):

<?php

function widers_verify(string $secret, string $rawBody, string $header): bool
{
    // header: "t=<unix>,v1=<hex>"
    parse_str(strtr($header, ',', '&'), $parts);
    $t = (int) ($parts['t'] ?? 0);
    $sig = (string) ($parts['v1'] ?? '');

    if (abs(time() - $t) > 300) {
        return false; // outside the 300s replay window
    }

    $expected = hash_hmac('sha256', $t . '.' . $rawBody, $secret);

    return hash_equals($expected, $sig);
}

طلبك الأول

اسرد جهات اتصالك بطلب واحد مصادَق:

curl https://console.widers.net/api/v1/contacts \
  -H "Authorization: Bearer wa_live_<id>|<token>" \
  -H "Accept: application/json"

حجوزات التقويم (مصادقة قديمة)

حجوزات التقويم سبقت طقم الـAPI هذا وتحتفظ بعقدها الخاص. وفيما يلي الفروق.
  • يصادِق بصلاحيات Sanctum القديمة، لا بالنطاقات أعلاه: bookings.read / bookings.write
  • يُرجِع غلاف Laravel الافتراضي، لا شكل data/error: {"data":[...]}
  • لا تصفّح بالمؤشّر، ولا وضع اختبار، ولا دعم لعدم التكرار — قائمته غير مصفّحة ومحدودة بسقف صارم.

مستعدّ لاستكشاف كل نقطة نهاية؟ راجِع مرجع الـAPI