تخطّ إلى المحتوى الرئيسي

نظرة عامة على Canvas API

أدر رحلات Canvas، وهي أتمتات متعددة الخطوات تُنشأ في منشئ الرحلات المرئي، عبر REST API.

جميع نقاط النهاية في هذه الصفحة نسبية إلى عنوان الأساس: https://api-eu1.joryio.com/api. راجع نظرة عامة على API.

المسار هو /journeys

توجد نقاط نهاية Canvas تحت المسار /journeys: اسم مورد API لـ canvas هو journey. يشير canvasId ومعرّف الرحلة إلى المعرّف نفسه.

المصادقة​

تتطلب جميع الطلبات مصادقة مفتاح API:

Authorization: Bearer jry_live_your_api_key_here
Content-Type: application/json

النطاقات المطلوبة لكل مجموعة نقاط نهاية:

النطاقنقاط النهاية
canvas:readالسرد والجلب والتنفيذات والإحصاءات وتحليلات العُقد والإصدارات
canvas:writeالإنشاء والتحديث والتكرار والأرشفة والوسوم والنسخ والتجارب
canvas:activateالتفعيل والإيقاف المؤقت والاستئناف والنشر وإعادة التشغيل وإدخال مستخدم والتراجع
canvas:enterإدخال مستخدم (مشغل API) - ولا شيء غير ذلك. مشمولة في canvas:activate
canvas:deleteالحذف والحذف المجمع

سرد الرحلات​

GET /journeys

معاملات الاستعلام​

المعاملالنوعالافتراضيالوصف
statusstring-الفلترة حسب الحالة
tagsstring-الفلترة حسب الوسوم، مفصولة بفواصل
qstring-بحث نص حر
createdBy / editedBystring-الفلترة حسب المنشئ/آخر محرر، معرّفات مستخدمين مفصولة بفواصل
pagenumber1رقم الصفحة
limitnumber-النتائج في الصفحة، حتى 100

طلب مثال​

curl -X GET "https://api-eu1.joryio.com/api/journeys?status=active&limit=20" \
-H "Authorization: Bearer jry_live_your_api_key"

الاستجابة​

{
"data": [
{ "id": "3c9d2f1a-5e8b-4a7c-9f0d-1b2a3c4d5e6f", "name": "Welcome journey", "status": "active" }
],
"pagination": {
"total": 8,
"page": 1,
"limit": 20,
"offset": 0,
"totalPages": 1,
"hasMore": false
}
}

إنشاء رحلة​

POST /journeys

نص الطلب​

الحقلالنوعمطلوبالوصف
namestringنعماسم الرحلة، بحد أقصى 255 حرفًا
descriptionstringلاالوصف، بحد أقصى 1000 حرف
nodesarrayلاعُقد الرسم البياني، بحد أقصى 500. قد تبدأ المسودة المنشأة بالمعالج فارغة
edgesarrayلاحواف الرسم البياني، بحد أقصى 1000
entryTriggerobjectلاكيفية دخول المستخدمين، راجع أدناه
variantsarrayلانسخ A/B/n للرحلة كاملة، راجع أدناه
settingsobjectلاtimezone وquietTime وconversionTracking وreEntryPolicy وpersonalizedVariants مع الإعداد
sendTypestringلاimmediate أو scheduled أو recurring أو trigger
scheduledAtstringلاتاريخ ISO 8601 لـ sendType: "scheduled"
recurringScheduleobjectلاfrequency (daily/weekly/monthly/custom) وcron وdayOfWeek وdayOfMonth وtimeOfDay وtimezone وendDate وmaxOccurrences ‏timeOfDay بصيغة HH:MM بنظام 24 ساعة (09:00، 17:30)؛ وتُرفض أي قيمة أخرى بالرمز 400.
targetingobjectلاجمهور الرحلات المجدولة/الفورية: userIds وfilterGroups وexcludeFilterGroups وfilterOperator وsubscriptionPreference
exitCriteriaobjectلاشكل الفلاتر نفسه لـ targeting؛ ويُخرج المستخدمون النشطون المطابقون
tagsstring[]لاالوسوم

بنية العُقدة​

يحمل كل إدخال في nodes حقول id وtype وconfig الخاص بالنوع وposition اختياريًا (x/y للمحرر). قيم type الصالحة:

trigger, message, in_app_message, delay, condition, behavior_split,
context, update_user, update_wallet, connector, experiment,
ai_decision, ai_agent

هناك عقدة message واحدة؛ والقناة هي config.channel (email وsms وpush وwhatsapp وviber وin_app وwebhook). أما أنواع العقد القديمة لكل قناة - email وsms وpush وwhatsapp وwhatsapp_message وwallet وwebhook والاسم البديل in_app - فقد أُزيلت وصارت مرفوضة عند الإنشاء والتحديث.

يحمل كل إدخال في edges حقول id وsource وtarget وsourceHandle / targetHandle / label اختيارية. يختار sourceHandle منفذ الإخراج في العُقد متعددة المخرجات، مثل مجموعات الفروع أو did / timed_out في behavior split.

مشغّل الدخول​

يحمل entryTrigger حقل type وإعداد config خاصًا بالنوع. الأنواع الصالحة: event وapi وentity_change وwhatsapp_inbound وsms_inbound وviber_inbound وattribute_change وsubscription_status وschedule.

دخول الشريحة ليس مشغّلًا. للدخول الناتج عن شيء فعله الشخص، استخدم مشغّل حدث مع فلتر؛ وللدخول الناتج عن مرور الوقت، استخدم رحلة متكررة على الشريحة.

نسخ الرحلة كاملة​

يحمل كل إدخال في variants: id وname وpercentage (من 0 إلى 100، ويجب أن يكون مجموع كل النسخ 100) وisControlGroup، إذ إن نسخة التحكم مجموعة محجوبة مقاسة بلا مسار، وtriggerNodeId، أي عُقدة المشغّل التي تنطلق منها نسخة المعالجة. راجع تحليلات الرحلات لطريقة عرض نتائج النسخ. كان اسم الحقل سابقًا isControl، ولا يزال هذا الاسم مقبولًا عند الكتابة ويُحوَّل إلى isControlGroup.

طلب مثال​

curl -X POST https://api-eu1.joryio.com/api/journeys \
-H "Authorization: Bearer jry_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "Welcome journey",
"sendType": "trigger",
"entryTrigger": {
"type": "event",
"config": { "eventName": "signed_up" }
},
"nodes": [
{ "id": "n1", "type": "trigger", "config": { "type": "event", "eventName": "signed_up" } },
{ "id": "n2", "type": "delay", "config": { "delayType": "duration", "value": 1, "unit": "days" } },
{ "id": "n3", "type": "email", "config": { "subject": "Welcome!", "html": "<p>Hi {{ user.firstName }}</p>" } }
],
"edges": [
{ "id": "e1", "source": "n1", "target": "n2" },
{ "id": "e2", "source": "n2", "target": "n3" }
]
}'

يعيد كائن الرحلة المُنشأ بحالة draft.


جلب رحلة​

GET /journeys/:canvasId
curl -X GET https://api-eu1.joryio.com/api/journeys/3c9d2f1a-5e8b-4a7c-9f0d-1b2a3c4d5e6f \
-H "Authorization: Bearer jry_live_your_api_key"

يعيد الرحلة كاملة، بما فيها nodes وedges وentryTrigger وvariants وsettings.


تحديث رحلة​

PUT /journeys/:canvasId

يقبل النص الحقول نفسها في إنشاء رحلة؛ كلها اختيارية ولا تُحدّث إلا الحقول المقدمة.

curl -X PUT https://api-eu1.joryio.com/api/journeys/3c9d2f1a-5e8b-4a7c-9f0d-1b2a3c4d5e6f \
-H "Authorization: Bearer jry_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "name": "Welcome journey v2" }'

حذف رحلة​

DELETE /journeys/:canvasId

يعيد 204 No Content. يفضّل أرشفة الرحلات ذات سجل التشغيل بدل حذفها عبر POST /journeys/:canvasId/archive، إذ توقف الأرشفة التسجيل والإرسال مع الاحتفاظ بالتحليلات.


نقاط نهاية الحالة​

الطريقةالمسارالنطاقالوصف
POST/journeys/:canvasId/activatecanvas:activateتفعيل؛ يمكن للمستخدمين البدء بالدخول
POST/journeys/:canvasId/pausecanvas:activateإيقاف مؤقت؛ يوقف الإدخالات الجديدة والتقدم
POST/journeys/:canvasId/resumecanvas:activateاستئناف رحلة موقفة
POST/journeys/:canvasId/archivecanvas:writeأرشفة، توقف التسجيل/الإرسال وتحفظ السجل
POST/journeys/:canvasId/unarchivecanvas:writeاستعادة إلى حالة غير مشغلة؛ فعّل صراحة للاستئناف
POST/journeys/:canvasId/publishcanvas:activateنشر المسودة الحالية كإصدار جديد. النص: changeSummary اختياري وuserTransition (keep_on_version / force_exit / migrate_to_new). فقط لرحلة مباشرة بالفعل (status: active)؛ وإلا 409 مع code: "journey_not_live" - يتم التفعيل الأول عبر POST /journeys/:canvasId/activate.
POST/journeys/:canvasId/reruncanvas:activateإعادة تشغيل الإصدار المنشور الحالي دون إنشاء إصدار جديد
curl -X POST https://api-eu1.joryio.com/api/journeys/3c9d2f1a-5e8b-4a7c-9f0d-1b2a3c4d5e6f/activate \
-H "Authorization: Bearer jry_live_your_api_key"

إدخال مستخدم (مشغّل API)​

سجّل مستخدمًا محددًا في رحلة؛ وهو مسار الإدخال لـ entryTrigger.type: "api".

POST /journeys/:canvasId/enter/:userId

الصلاحية: canvas:enter (مشمولة في canvas:activate)، كي يتمكن تكامل مثل Zapier من إضافة أشخاص إلى رحلة دون القدرة على تشغيلها أو إيقافها مؤقتًا أو تعديلها.

النص اختياري: context، وهو كائن JSON متاح للتنفيذ ويمكن قراءته في الرسائل والشروط كمتغيرات سياق الرحلة.

curl -X POST https://api-eu1.joryio.com/api/journeys/3c9d2f1a-5e8b-4a7c-9f0d-1b2a3c4d5e6f/enter/user_123 \
-H "Authorization: Bearer jry_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "context": { "source": "crm-sync", "priority": "high" } }'

قائمة الرحلات التي يمكن إدخال شخص إليها​

GET /journeys/enterable?q=

الرحلات النشطة (active) بالشكل { "data": [{ "id", "name", "activatedAt" }] }، مرتبة حسب الاسم، 100 كحد أقصى؛ ويرشّح q بجزء من الاسم. الصلاحية: canvas:enter (أو canvas:read) - يمكن للتكامل المسموح له بإضافة أشخاص إلى الرحلات اختيار رحلة دون قراءة الرحلات نفسها.


التنفيذات والتحليلات​

الطريقةالمسارالوصف
GET/journeys/:canvasId/executionsسرد التنفيذات، status وlimit حتى 100 وoffset
GET/journeys/:canvasId/executions/:executionIdجلب تنفيذ واحد. تحمل كل خطوة Webhook في history الحقل webhook (الحالة، النجاح، المدة، المحاولات، الخطأ، الحقول المحفوظة)؛ ويضيف الاستدعاء الفاشل (ليس 2xx) الحقل webhook.response ({ status, contentType, body, truncated }) - مع إخفاء الأسرار، وأول 2 KB من النص، ويُحفظ 30 يومًا، ولا يُعاد إلا لمن يملك pii:view (ومفتاح API فقط مع هذه الصلاحية؛ ويحصل الآخرون على webhook.responseHidden: true). لا يُخزَّن نص الاستجابة الناجحة أبدًا
GET/journeys/:canvasId/executions/:executionId/contextمتغيرات سياق التنفيذ مع الأنواع المستنتجة
GET/journeys/:canvasId/statsإحصاءات مستوى الرحلة، startDate وendDate
GET/journeys/:canvasId/node-analyticsتحليلات لكل عُقدة، startDate وendDate
GET/journeys/:canvasId/variant-statsأداء نسخ الرحلة كاملة، A/B/n والتحكم
GET/journeys/:canvasId/recovered-cartsالسلال المتروكة التي استعادتها الرحلة - القائمة التي خلف revenue.recoveredCarts في /stats، من الاستعلام نفسه، لذا فإن total يساوي ذلك العدد للقيم نفسها من startDate/endDate (السلال المستعادة ضمن النطاق؛ النهاية بتاريخ فقط تشمل اليوم كله، بالمنطقة الزمنية لمساحة العمل). limit من 1 إلى 100 (الافتراضي 25)، وoffset؛ الأحدث أولًا. الصفوف: orderNumber (رقم المتجر)، placedAt، recoveredAt، match (recovery_link، order = السلة نفسها، reported)، cartValue/cartCurrency، creditedRevenue/creditedCurrency (صافٍ بعد المبالغ المستردة)، contact (صاحب السلة) وbuyer (فقط عندما سُجّل الطلب باسم شخص آخر)؛ تُخفى أسماء جهات الاتصال من دون pii:view. يُرجع { data, total, limit, offset, summary }
GET/journeys/:canvasId/experiments/:nodeId/statsإحصاءات عُقدة التجربة مع اختبار الدلالة
POST/journeys/:canvasId/experiments/:nodeId/declare-winnerإعلان فائز، النص pathId
POST/journeys/:canvasId/experiments/:nodeId/resetإعادة تجربة إلى جمع البيانات
GET/journeys/:canvasId/personalization-statusحالة مرحلة النسخ المخصصة

نقاط نهاية إضافية​

الطريقةالمسارالوصف
PUT/journeys/:canvasId/variantsضبط نسخ الرحلة كاملة، نص variants
GET/journeys/:canvasId/versionsسرد الإصدارات
GET/journeys/:canvasId/versions/compare?v1=&v2=مقارنة إصدارين
GET/journeys/:canvasId/versions/compare-draftمقارنة المسودة الحالية بآخر إصدار منشور
GET/journeys/:canvasId/versions/migration-previewمعاينة توافق التنفيذ قبل نشر مع ترحيل
GET/journeys/:canvasId/versions/:versionIdجلب إصدار
POST/journeys/:canvasId/versions/:versionId/rollbackالتراجع إلى إصدار. للرحلات المباشرة فقط؛ وإلا 409 journey_not_live.
GET/journeys/:canvasId/versions/:versionId/statsإحصاءات خاصة بإصدار
GET/journeys/:canvasId/versions/:versionId/executionsتنفيذات إصدار محدد
GET/journeys/:canvasId/version-execution-countsأعداد التنفيذات لكل إصدار
POST/journeys/:canvasId/versions/:versionId/migrateترحيل التنفيذات المتوافقة قسرًا إلى إصدار
GET/journeys/:canvasId/historyسجل التدقيق، limit حتى 200
POST/journeys/bulk-delete / bulk-duplicate / bulk-archive / bulk-unarchiveإجراءات مجمعة؛ النص { "ids": [...] } ويعيد { succeeded, failed }
POST/journeys/bulk-tagإضافة وسوم مجمعة؛ النص { "ids": [...], "tags": [...] }
POST/journeys/webhook/testتشغيل إعداد عُقدة Webhook مرة وإرجاع الاستجابة الحية مع الطلب المرسل (بيانات الاعتماد مخفية). يعرض user.userId جهة اتصال حقيقية من مساحة العمل تمامًا كالإرسال الفعلي، وإلا تُستخدم قيم عينة، مع تحديد للمعدل
POST/journeys/preview-context-valueعرض تعبير Liquid بسياق عينة
POST/journeys/preview-user-updatesتشغيل تجريبي لصفوف عُقدة Update User على مستخدم عينة
POST/journeys/preview-user-update-jsonتشغيل تجريبي لـ JSON المخصص في عُقدة Update User: المدخل { json, sample } والمخرج { errors, preview: { errors, result } }. تمنع errors الحفظ أو التفعيل؛ وpreview هو الـ JSON معروضًا على العينة. لا يكتب شيئًا
POST/journeys/:canvasId/nodes/:nodeId/send-test-email / send-test-sms / send-test-whatsapp / send-test-pushإرسال اختباري لعُقدة رسالة
POST/journeys/:canvasId/cleanup-stuck-executionsتنظيف التنفيذات العالقة
GET/journeys/:canvasId/executions/:executionId/rendered-message/:nodeIdالرسالة المعروضة لتنفيذ وعُقدة محددين

مراجعة الإطلاق​

المراجعة نفسها التي تسبق الإرسال في الحملات (انظر دليل مراجعة الإطلاق)، تعمل على كل عقدة رسالة: رابط إلغاء الاشتراك، حقول الدمج، توثيق المرسل، الروابط غير الصالحة، طول الموضوع، النسخة النصية المفقودة، ساعات الهدوء، إضافة إلى node_unreachable للعقد التي لا يصل إليها أي مشغّل، وcart_variable_no_cart_trigger لرسالة تقرأ cart في رحلة لا تبدأ بحدث سلة، وchannel_not_set_up لقناة تستخدمها الرحلة وليس لها مزوّد أو مُرسِل (params.channel؛ عائق، أو توصية مع params.sandbox: 1 في مساحة عمل تجريبية حيث تُحاكى الإرسالات للجميع). يشغّلها التفعيل والنشر أيضًا.

GET /journeys/{canvasId}/launch-review

النطاق: canvas:read. للاستجابة البنية الموثقة في واجهة الحملات؛ تحمل نتيجة العقدة scope.kind = "node" وscope.id = معرّف العقدة وfix.nodeId.

عندما تتطلب مساحة العمل قائمة نظيفة (settings.launchReview.requireClean، افتراضيًا true) وتوجد عوائق، يجيب POST /journeys/{canvasId}/activate وPOST /journeys/{canvasId}/publish بـ 409 مع code: "launch_review_blocked" والعوائق في الجسم.

استجابات الأخطاء​

تشترك جميع الأخطاء في الشكل القياسي. راجع استجابة الخطأ في نظرة API العامة لمعرفة التنسيق ورموز الحالة وسلوك تحديد المعدل.

{
"statusCode": 404,
"message": "Canvas with ID 8f14e45f-ceea-467f-a11d-2f4b6a1c9e3b not found",
"timestamp": "2026-07-12T09:00:00.000Z",
"path": "/journeys/8f14e45f-ceea-467f-a11d-2f4b6a1c9e3b"
}

ذو صلة​