Subscriptions API
Subscriptions API هي واجهة الموافقة في Joryio. تدير، لكل جهة اتصال، حالة الموافقة أو الإلغاء في كل قناة رسائل، Email وSMS وWhatsApp وPush وViber، وعضوية قوائم الاشتراك، أي فئات أو موضوعات الموافقة، وحالة ارتداد Email وسجل التدقيق الكامل لتغييرات الموافقة.
تغطي الصفحة ثلاثة موارد:
- موافقة جهة الاتصال:
/subscriptions/contacts/...لقراءة موافقة القناة والقائمة لجهة اتصال وتغييرها. - قوائم الاشتراك:
/listsلإنشاء القوائم وإدارتها وإجراء عمليات عضوية جماعية. - صفحة التفضيلات المستضافة:
/subscriptions/hosted-pageلتأليف صفحة مركز التفضيلات لمساحة العمل.
كل النقاط هنا نسبية إلى عنوان الأساس https://api-eu1.joryio.com. راجع نظرة عامة على API.
المصادقة
تتطلب كل الطلبات مفتاح API، وتعمل جلسة لوحة تحكم JWT أيضاً:
Authorization: Bearer jry_live_your_api_key_here
Content-Type: application/json
النطاقات لكل نقطة نهاية
| نقطة النهاية | النطاق |
|---|---|
GET /subscriptions/contacts/:userId و/lists و/history و/channels/:channel/status و/email-valid | compliance:read |
PUT /subscriptions/contacts/:userId/channels/:channel وPOST /clear-bounce وPOST / DELETE لعضوية قائمة جهة اتصال | compliance:write |
POST /lists وPUT / DELETE للقوائم وPOST /restore وعمليات الأعضاء الجماعية | settings:write |
GET /lists وGET /lists/:listId وGET /lists/:listId/stats | settings:read |
GET /lists/:listId/members | compliance:read |
GET /subscriptions/hosted-page/preference-center وPOST /preview | settings:read |
PUT /subscriptions/hosted-page/preference-center | settings:write |
المفاهيم الأساسية
معرّف جهة الاتصال
كل مسار /subscriptions/contacts/:userId يأخذ معرّف جهة الاتصال الداخلي في Joryio، وهو id في Users API، وليس userId الخارجي الذي ترسله في الأحداث. يجب أن يكون ObjectId سداسياً من 24 حرفاً أو UUID؛ ويُرفض غير ذلك بـ 400 Bad Request.
الاشتراك وقت الإنشاء
يمكنك اشتراك جهة اتصال في قوائم في طلب إنشاء المستخدم نفسه: يقبل POST /users مصفوفة subscriptions اختيارية. تبقى نقاط هذه الصفحة الطريقة لإدارة الموافقة بعد الإنشاء: PUT /subscriptions/contacts/:userId/channels/:channel لموافقة القناة وPOST /subscriptions/contacts/:userId/lists/:listId لعضوية القائمة. لا تعيد اشتراكات الإنشاء إحياء إلغاء قائم؛ إعادة الموافقة الصريحة تتطلب POST لعضوية القائمة.
القنوات وحالاتها
القنوات الخمس هي email وsms وwhatsapp وpush وviber؛ وأي قيمة أخرى تعيد 400.
| الحالة | الوصف |
|---|---|
optedIn | موافقة صريحة، مثل تأكيد الموافقة المزدوجة. |
subscribed | مشترك، موافقة مفردة أو افتراضية. |
unsubscribed | ألغى الاشتراك. |
الحالات بصيغة camelCase، أي optedIn لا opted_in. تعامل بوابات الإرسال جهة الاتصال بلا حالة مسجلة لقناة كأنها مشتركة؛ غياب السجل ليس إلغاءً.
التغييرات مدققة ومعكوسة في السجلات
تسجل كل كتابة في API في سجل تدقيق الاشتراكات لجهة الاتصال، بالمصدر وIP وuser agent وهوية مفتاح API أو المشرف، ويمكن استرجاعها من سجل الاشتراك. تُعكس الإلغاءات أيضاً إلى دفاتر منع مرتبطة بالمعرّف: إلغاء SMS أو WhatsApp يتبع رقم الهاتف، وإلغاء Email يتبع العنوان في مساحة العمل، لذلك تغطى جهات الاتصال المكررة أيضاً. راجع Suppressions API.
موافقة جهة الاتصال
الحصول على اشتراكات جهة اتصال
GET /subscriptions/contacts/:userId
يعيد حالة موافقة كل قناة وعضويات القوائم. تكون القنوات بلا حالة مسجلة غائبة ببساطة من channels. يحمل Email حقول الارتداد الإضافية: isValid وbounceType وbounceCount وlastBounceAt. يعيد lists أول 500 صف عضوية للجهة. يعيد 404 إن لم توجد جهة الاتصال في مساحة العمل.
تحديث اشتراك قناة
PUT /subscriptions/contacts/:userId/channels/:channel
| الحقل | النوع | مطلوب | الوصف |
|---|---|---|---|
channel | string | نعم | يجب أن يطابق القناة في URL؛ قيمة URL هي الفائزة عند الاختلاف. |
status | string | نعم | optedIn أو subscribed أو unsubscribed. |
source | string | لا | مصدر التغيير، مثل api أو preference_center؛ الافتراضي api. |
consentText | string | لا | نص الموافقة المعروض عند الاشتراك، يحفظ للامتثال. |
reason | string | لا | سبب نصي حر يحفظ في سجل التدقيق. |
{
"channel": "email",
"status": "unsubscribed",
"source": "preference_center",
"reason": "User requested via support ticket"
}
يعيد كائن channels المحدّث بالكامل.
- تؤدي الموافقة على Email إلى مسح حالة ارتداد مؤقت فقط، ولا تحيي ارتداداً دائماً؛ استخدم مسح حالة الارتداد لذلك.
- يُعكس إلغاء
smsأوwhatsappفي دفتر المنع المرتبط بالهاتف، ويُعكس تغيير Email في الدفتر المرتبط بالعنوان لمساحة العمل. - تُدقق العملية مع IP وuser agent وهوية المفتاح أو المشرف.
مسح حالة الارتداد
أعد ضبط ارتداد Email وارفع منع قابلية التسليم المرتبط بالعنوان. وهي الطريقة المعتمدة لرفع ارتداد دائم؛ لا تفعلها إعادة اشتراك المستلم.
POST /subscriptions/contacts/:userId/clear-bounce
يقبل reason اختيارياً، ويعيد { "success": true }. يمسح bounceType وbounceCount وlastBounceAt ويعيد isValid إلى true، ويحذف أيضاً صفوف hard_bounce وcomplaint لعنوان Email من دفتر المنع لمساحة العمل؛ فينطبق المسح على كل جهات الاتصال المكررة ذات العنوان نفسه.
الحصول على اشتراكات القوائم
GET /subscriptions/contacts/:userId/lists
يعيد كل صفوف عضوية قوائم جهة الاتصال، المشتركة والملغاة. تكون العضوية فريدة لكل جهة اتصال + قائمة + قناة؛ يمكن للجهة أن تكون مشتركة في قائمة على email وملغية منها على sms كسجلين منفصلين.
اشتراك جهة اتصال في قائمة
POST /subscriptions/contacts/:userId/lists/:listId
الطلب idempotent؛ تؤكد إعادة الطلب الاشتراك. وهو مسار إعادة الموافقة الصريح والمدقق الوحيد الذي يمكنه إعادة اشتراك جهة ألغت القائمة، إذ لا تفعل الإضافة الجماعية ذلك.
| الحقل | النوع | مطلوب | الوصف |
|---|---|---|---|
channel | string | نعم | email أو sms أو whatsapp أو push أو viber. |
source | string | لا | مثل api أو form أو import أو preference_center؛ الافتراضي api. |
consentText | string | لا | نص الموافقة المعروض. |
يعيد صف العضوية المنشأ أو المحدّث.
إلغاء جهة اتصال من قائمة
DELETE /subscriptions/contacts/:userId/lists/:listId
تمر القناة في نص الطلب لا URL:
{ "channel": "email", "source": "preference_center" }
يعيد { "success": true }. إذا لم يكن للجهة صف عضوية للقائمة والقناة، ينشئ النظام صف unsubscribed صريحاً على أي حال؛ فلا يفقد سحب الموافقة بصمت وتمنع بوابة الإرسال إرسالات القائمة لاحقاً.
الحصول على سجل الاشتراك
GET /subscriptions/contacts/:userId/history
| المعامل | النوع | الافتراضي | الوصف |
|---|---|---|---|
limit | number | 50 | مدخلات الصفحة؛ القيم غير الرقمية ترجع للافتراضي. |
offset | number | 0 | إزاحة الترقيم. |
يعيد items، الأحدث أولاً، وtotal. يحتوي كل مدخل على القناة والقائمة، إن وجدت، وaction والحالة السابقة والجديدة والمصدر وIP وuser agent ونص الموافقة وmetadata ووقت الإنشاء. تكون action إحدى subscribe وunsubscribe وresubscribe وbounce وhard_bounce وsoft_bounce وcomplaint وimport وapi_update.
فحص حالة اشتراك قناة
GET /subscriptions/contacts/:userId/channels/:channel/status
يعيد { "subscribed": true } ما لم تكن جهة الاتصال unsubscribed صراحة في القناة؛ الجهة بلا حالة مسجلة تعد مشتركة. يعيد معرّف جهة اتصال غير معروف { "subscribed": false } لا 404.
فحص صلاحية Email
GET /subscriptions/contacts/:userId/email-valid
يعيد { "valid": true }. تكون valid خاطئة فقط عندما يجعل ارتداد دائم العنوان غير صالح. يعيد معرّف غير معروف { "valid": false } لا 404. يقيس هذا قابلية التسليم لا الموافقة، فتظل الجهة الملغية ذات العنوان العامل true.
قوائم الاشتراك
القوائم فئات أو موضوعات الموافقة التي يشترك بها الأشخاص، مثل النشرة وتحديثات المنتج. تعيش تعريفاتها تحت /lists، وتدار العضوية لكل جهة بنقاط الموافقة أعلاه أو بالنقاط الجماعية أدناه.
إنشاء قائمة
POST /lists
| الحقل | النوع | مطلوب | الوصف |
|---|---|---|---|
name | string | نعم | اسم القائمة، حتى 255 حرفاً وفريد لكل مساحة عمل. |
description | string | لا | وصف، حتى 1000 حرف. |
channels | string[] | لا | القنوات التي تنطبق عليها القائمة؛ الافتراضي ["email"]. |
isPublic | boolean | لا | تظهر في مركز التفضيلات؛ الافتراضي true. |
type | string | لا | marketing أو transactional؛ الافتراضي marketing. |
requireDoubleOptIn | boolean | لا | طلب موافقة مؤكدة؛ الافتراضي false. |
يعيد كائن القائمة، وهو يشمل isDefault لفئة التسويق الافتراضية المنشأة تلقائياً وsenderId عند كون القائمة مجموعة اشتراك SMS أو WhatsApp لكل رقم مرتبطة بمرسل.
عرض القوائم والحصول عليها
GET /lists
GET /lists/:listId
يدعم العرض includeArchived=true لإدراج المؤرشفة ويعيد القوائم الأحدث أولاً بحد 200. يعيد الحصول على قائمة 404 إن لم توجد أو كانت مؤرشفة.
تحديث قائمة أو أرشفتها
PUT /lists/:listId
DELETE /lists/:listId
POST /lists/:listId/restore
يقبل PUT أي مجموعة فرعية من حقول الإنشاء. يؤرشف DELETE بحذف ناعم ويضبط archivedAt مع حفظ صفوف العضوية، ويعيد 204 No Content. يعيد مسار restore كائن القائمة المستعاد.
الحصول على أعضاء قائمة
GET /lists/:listId/members
| المعامل | النوع | الافتراضي | الوصف |
|---|---|---|---|
channel | string | - | فلتر اختياري لقناة. |
status | string | - | subscribed أو unsubscribed. |
limit | number | 50 | الصفوف في الصفحة. |
offset | number | 0 | إزاحة الترقيم. |
يعيد members وtotal، ويضم كل عضو معرّف جهة الاتصال والقائمة والقناة والحالة وتواريخ الاشتراك ومصدره وسياق المنظمة ومساحة العمل.
إحصاءات قائمة
GET /lists/:listId/stats
يعيد total وbyChannel وsubscribed وunsubscribed. يعد byChannel العضويات غير الملغاة لكل قناة.
إضافة أعضاء جماعياً
أضف حتى 10,000 جهة اتصال إلى قائمة على قناة واحدة:
POST /lists/:listId/members/bulk
| الحقل | النوع | مطلوب | الوصف |
|---|---|---|---|
contactIds | string[] | نعم | معرّفات جهات اتصال Joryio، حتى 10,000. |
channel | string | نعم | قناة القائمة. |
source | string | لا | يسجل كـ optInSource. |
يعيد { "added": 2, "updated": 0, "skippedUnsubscribed": 0 }. تنشئ الإضافة الجماعية عضويات جديدة فقط؛ تترك القائمة القائمين كما هم، ولا تعيد اشتراك من ألغى صراحة. يظهر هؤلاء في skippedUnsubscribed. استخدم نقطة الاشتراك الصريحة لإعادة الموافقة. يبقى updated صفراً للتوافق الخلفي.
إزالة أعضاء جماعياً
ألغِ اشتراك حتى 10,000 جهة اتصال من قائمة على قناة واحدة:
DELETE /lists/:listId/members/bulk
يمر contactIds وchannel في النص ويعيد { "removed": 1 }. تقلب العملية صفوف العضوية إلى unsubscribed، ولا تحذفها، فيبقى أثر التدقيق وتُمنع الإرسالات المستقبلية للقائمة.
صفحة التفضيلات المستضافة
API لتأليف صفحة مركز التفضيلات المستضافة لمساحة العمل، التي يصل إليها المستلم من رابط إلغاء الاشتراك أو التفضيلات. العرض العام للصفحة يخدمه مسارات عامة بالرمز لا مفتاح API، وليس جزءاً من هذا المرجع.
الحصول على قالب مركز التفضيلات
GET /subscriptions/hosted-page/preference-center
يعيد type وmode وhtml وredirectUrl وdesignJson وupdatedAt. تكون mode إحدى:
default: صفحة Joryio المدمجة.custom: قالب HTML/Liquid الخاص بك.dnd: محرر مرئي، مع HTML المعروض نفسه.redirect: سجل الإلغاء ثم أعد التوجيه إلىredirectUrl.
تحديث قالب مركز التفضيلات
PUT /subscriptions/hosted-page/preference-center
| الحقل | النوع | الوصف |
|---|---|---|
mode | string | default أو custom أو dnd أو redirect. |
html | string | جسم HTML/Liquid للوضعين custom وdnd، حتى 100KB؛ يجب أن يتضمن موضع {{ preferences_form }}. |
redirectUrl | string | هدف وضع redirect، حتى 2048 حرفاً. |
designJson | object | حالة المحرر المرئي لدوران dnd؛ تُمسح في الأوضاع الأخرى. |
يعيد القالب المحفوظ بشكل استجابة GET نفسه.
معاينة قالب
POST /subscriptions/hosted-page/preview
النص { "html": "..." } هو القالب للعرض ببيانات نموذجية. تعيد الاستجابة { "html": "<rendered, sanitized html>" }.
واجهات ذات صلة، ليست في الصفحة
- نقاط المستلم: إلغاء بنقرة واحدة،
POST /u/:token، وصفحات التفضيلات المستضافة هي نقاط عامة مصادق عليها برمز، لا بمفتاح API. - Web SDK:
POST /v1/subscriptions/channelوPOST /v1/subscriptions/groupتصادقان بمفتاح SDK فيX-SDK-Key. راجع دليل إدارة الاشتراكات. - webhooks الموفرين: ارتدادات Email وكلمات SMS الواردة،
/webhooks/email/...و/webhooks/sms/...، تكاملات موفرين يتحقق توقيعها. - المنع: دفتر عدم الإرسال لمساحة العمل له Suppressions API خاص به.
الخطوات التالية
- Users API - أنشئ جهة الاتصال قبل ضبط الموافقة.
- Suppressions API - دفتر عدم الإرسال المرتبط بالمعرّف.
- دليل إدارة الاشتراكات - المفاهيم واستخدام SDK والكلمات المفتاحية والامتثال.