تعرض Salla Order Reservations API قراءة فقط للحجوزات الحالية للطلبات ضمن نافذة تواريخ. وهذا يجعلها مفيدة لمطابقة التقويم وERP والتشغيل، لكنها ليست محرك Availability ولا تمنع بمفردها نظامين من بيع المقعد أوالفترة الزمنية نفسها. النمط الآمن هو إدخال الحجوزات في Local Projection مطبّعة، وكشف تعارض الفترات والسعة، وإرسال التغييرات إلى الأنظمة الأخرى عبر Idempotent Outbox، ثم مطابقة Projection دوريًا مع Salla.
هذا شرح هندسي عملي قائم على الوثائق، وليس إعلان منتج أوخبرًا. الـEndpoint والـScope وحقول الاستجابة أدناه حقائق موثقة في صفحات Salla Merchant API الرسمية، وتم التحقق منها في 29 أكتوبر 2026. أما نموذج التطبيع وقواعد التعارض والـOutbox وخطة Reconciliation فهي توصيات هندسية، وليست ادعاءات عن سلوك غير موثق في Salla.
الخلاصة أولًا
استخدم GET /admin/v2/reservations مع نافذة محدودة من start وend وToken يملك orders.read. احفظ كل Reservation بهوية مركبة من Merchant وReservation ID، وطبّع الفترة الزمنية وفق Time Zone الموثقة للمتجر، واحتفظ بـtype وseats_count ورابط الطلب وSource Timestamps. أرسل تغييرات Calendar أوERP عبر Outbox، ثم أعد قراءة النافذة نفسها لاكتشاف Drift.
لا تعامل List Endpoint كـCommand API. العملية الموثقة تسترجع الحجوزات الحالية؛ ولا توثق إنشاء Reservation أوقفل Capacity أوحل التنافس. يجب أن يكون للـAvailability مصدر سلطة واحد صريح، وتصبح بقية الأنظمة Projections عنه.
| المجال | السلطة المقترحة | الدليل المحفوظ |
|---|---|---|
| مراقبة الحجز | Salla Order Reservations read endpoint | Reservation ID والنوع والبداية والنهاية والمقاعد ووقت القراءة |
| السعة القابلة للبيع | نظام المنتج أوالحجز الذي يملك Availability | Capacity Version وقرار قبول الحجز |
| عرض التقويم | External Projection قابلة للتكرار بأمان | Provider Event ID وSource Reservation ID وآخر Digest |
| سير عمل ERP | Projection للطلب أوالمهمة | External Document ID ومرجع الطلب |
| إصلاح Drift | Salla Reconciliation مجدولة | Window Cursor والمعرفات المرئية وحد الغياب والنتيجة |
ابدأ من العقد الموثق
توثق Salla المسار GET https://api.salla.dev/admin/v2/reservations باسم List Order Reservations. وتقول الصفحة إن Endpoint تسترجع حجوزات الطلبات الحالية، وتتطلب Scope باسم orders.read، وتعرض مثالًا لمعاملَي التاريخ start وend. تشمل أمثلة الاستجابة الموثقة:
id: هوية الحجز؛title: عنوانًا للعرض؛type: وتعرض الأمثلةdayوtime؛startوend: فترة الحجز؛seats_count: عدد المقاعد في الحجز؛url: رابط Dashboard للطلب في المثال؛created_at: وقت الإنشاء لدى المصدر.
تذكر الصفحة أنها عُدلت في 7 سبتمبر 2026. ويذكر Changelog لدى Salla بشكل منفصل أن Order Details وكل Order Webhooks تدعم product_reservations. يفيد ذلك للاكتشاف المعتمد على الأحداث، لكنه لا يجعل Webhook Delivery سجلًا تاريخيًا كاملًا. استخدم Events لتقليل Latency، واستخدم Reservations Endpoint لمطابقة الحقيقة ضمن نافذة محدودة.
لا تنص الوثائق العامة التي تمت مراجعتها على أن Endpoint:
- تكتب الحجوزات أوتلغيها؛
- تضمن Resource-capacity Lock؛
- تعيد Resource ID مناسبًا لتجميع التعارض؛
- تحدد ما إذا كانت حدود الفترة Inclusive أوExclusive؛
- تعرّف Time-zone Offset لكل Timestamp؛
- تضمن أن كل Webhook Delivery تساوي Business Transition واحدة.
تعامل مع هذه النقاط كقرارات تكامل أومعلومات مجهولة. تحقق من إعداد المتجر والمنتج في بيئة منضبطة قبل السماح بإجراءات Downstream مؤتمتة.
افصل Observation عن Availability
من الأخطاء الشائعة أن تعتقد ثلاثة أنظمة أنها تملك الجدول. يقبل Storefront الحجز، ويعدّل الموظف Shared Calendar يدويًا، وينشئ ERP أمر عمل. ثم تنحرف الحالات مع الوقت.
استخدم ثلاث طبقات صريحة:
- Availability Authority: النظام الذي يقرر هل يمكن بيع مقعد أوفني أوغرفة أوTime Slot.
- Reservation Observation: السجل المطبّع المقروء من Salla والمرتبط بسياق الطلب.
- Operational Projections: Calendar Events ومهام ERP والتنبيهات واللوحات المشتقة من Observation.
لا تجعل Calendar سلطة ضمنية لأن الموظفين يستطيعون سحب Event. إذا كانت Manual Calendar Edits مهمة، فمررها عبر Command Path مراجعة تحدّث مالك Availability الفعلي. وإلا فاكتب Projection الصحيحة من جديد أوارفع Drift للمراجعة.
ابن Projection ثابتة للحجز
افصل Source Data عن Derived Data. يمكن أن يبدو السجل المحايد عن Provider هكذا:
{
"tenant_key": "merchant-42",
"provider": "salla",
"reservation_id": "1473353380",
"reservation_type": "time",
"title": "Service appointment",
"start_local": "2026-11-03T10:00:00",
"end_local": "2026-11-03T10:30:00",
"source_timezone": "Asia/Riyadh",
"start_utc": "2026-11-03T07:00:00Z",
"end_utc": "2026-11-03T07:30:00Z",
"seats": 1,
"source_order_url": "redacted-or-access-controlled",
"source_created_at": "2026-10-29T13:48:33+03:00",
"observed_at": "2026-10-29T17:05:12Z",
"source_digest": "sha256:..."
}هذا مثال تصميم للتطبيق وليس Salla Payload. احفظ Time Zone الخاصة بالمتجر من Authoritative Configuration، وارفض Local Times الملتبسة بدل التخمين. حوّل إلى UTC للمقارنة، لكن احتفظ بالقيم المحلية الأصلية للتدقيق والعرض للعميل.
استخدم Compound Uniqueness Key مثل (tenant_key, provider, reservation_id). لا تسمح بتصادم Reservation IDs بين المتاجر. واحسب Digest من Source Fields المطبّعة فقط حتى تصبح القراءة المكررة No-op.
عرّف قواعد تعارض الفترة والسعة
طبّع Time Reservations إلى Half-open Intervals: [start, end). تتداخل فترتان عندما:
a.start < b.end AND b.start < a.endتسمح Half-open Boundaries بأن ينتهي حجز في اللحظة التي يبدأ فيها التالي. هذه قاعدة مقارنة محلية، وليست ادعاءً عن Boundary Semantics غير الموثقة في Salla.
يحتاج Conflict Grouping إلى Resource Key: منتج أوخدمة أوغرفة أوموظف أوCapacity Pool. لا يعرض مثال List هذا المفتاح، لذلك اشتقه فقط من Mapping موثقة للطلب أوالمنتج أومن Configuration صريحة. لا تجمع الحجوزات عبر Title Text.
في Capacity Pool، اجمع المقاعد في كل الحجوزات النشطة المتداخلة وقارن أعلى Concurrent Total بالسعة المضبوطة. تستهلك seats_count=2 وحدتين وليس Event واحدة. عند فقد Capacity أوResource Identity، علّم السجل unclassified وأوقف القبول أوالإلغاء الآلي.
تحتاج Day Reservations إلى سياسة منفصلة. وسّعها إلى Business-day Interval في Time Zone المتجر، لاTime Zone خادم التكامل. عالج Daylight-saving Transitions للمتاجر خارج السعودية، ولا تفترض أن كل Local Day مدته 24 ساعة UTC.
اجمع Webhooks وReconciliation
Webhooks إشارة سريعة وليست آلية التعافي الوحيدة. تقول وثائق Salla Webhooks إن Receiver يجب أن يستجيب خلال 30 ثانية، وتصف Retries عند فشل Delivery. لذلك يجب أن يصادق Receiver الطلب، ويحفظ Raw Event بشكل دائم، ويرد بسرعة، ثم يعالج Asynchronously.
Workflow مقترحة:
- تحقق من Webhook وفق Security Guidance الحالية لدى Salla.
- احفظ Immutable Inbox Record تحوي Tenant وEvent Type وSource IDs وPayload Digest.
- نفذ Deduplication بمفتاح Delivery أوBusiness Key ثابت متاح في Event Model.
- أرسل Narrow Refresh للطلب أوReservation Window المتأثرة.
- نفذ Upsert للـNormalized Reservation Projection.
- أنشئ Outbox Rows لمستهلكي Calendar وERP والتنبيهات.
- علّم Inbox Item مكتملة فقط بعد Durable Commit.
يمكن لأحداث الطلب التي تشمل product_reservations تحديد التغييرات المحتملة. ومع ذلك جدول List Reads دورية، لأن Events قد تتأخر أوتتكرر أوتغيب أثناء الصيانة أوتكون قد فاتت قبل تثبيت التكامل.
طابق نوافذ تواريخ محدودة
لا تشغّل Job غير محدودة لقراءة كل شيء. قسّم حسب Merchant وDate Window واحفظ Checkpoints:
window = [today - lookback, today + horizon]
GET reservations?start=window.start&end=window.end
normalize every returned record
upsert by merchant + reservation_id
mark each returned ID as seen in this run
compare local active records inside the same window
quarantine missing records before declaring deletion
emit outbox changes
advance checkpoint only after commitتغطي Lookback التغييرات المتأخرة، وتغطي Future Horizon العمل القادم. اخترهما من Business Lead Times لاConstant عامة اعتباطية. واستخدم Grace Rule قبل اعتبار Missing Item محذوفة؛ فلا يجب أن يحذف API Failure مؤقت أوتغير في Filter Semantics أوصفحة غير مكتملة Calendar Events فورًا.
سجل Request Window وHTTP Status وعدد النتائج وRun ID وCompletion Time. إذا انتهت مهلة Endpoint، فإن Read قابلة للتكرار، لكن Job المحيطة يجب أن تبقى Idempotent حتى لا تكرر Downstream Events.
أرسل إلى Calendar وERP بأمان
أنشئ Outbox Row واحدة لكل Destination وReservation Digest. يجعل Idempotency Key مثل tenant:reservation:destination:source_digest التوصيل المكرر آمنًا. احفظ Event أوDocument ID لدى الوجهة بعد النجاح.
إذا انتهت مهلة Calendar Request فنتيجتها Unknown. اقرأ بالمفتاح الخارجي الثابت قبل إنشاء Event أخرى، ولا تفترض فشل الطلب الأول. وفي Updates قارن Last Applied Digest وعدّل الحقول المتغيرة فقط. وعند الإزالة انتقل إلى Cancelled أوTentative State قابلة للعكس قبل Hard Delete إن كانت الوجهة تدعم ذلك.
احفظ Order Dashboard URLs في سجلات محكومة الوصول. لا تضعها في Public Calendar Descriptions أوAnalytics Labels أوError Messages. أرسل أقل بيانات عميل لازمة للـDownstream Workflow.
جدول القرار
| الحالة | الإجراء الآمن | الاختصار غير الآمن |
|---|---|---|
| نفس Reservation ID وDigest | No-op | إعادة كتابة كل الوجهات |
| نفس ID مع تغير الفترة أوالمقاعد | تحديث Projection وOutbox | إنشاء Calendar Event ثانية |
| حجز متداخل جديد دون تجاوز السعة | Project طبيعيًا وسجل Utilization | اعتبار كل Overlap خطأ |
| المقاعد المتزامنة تتجاوز السعة | أوقف التأكيد الآلي ونبه المالك | إلغاء طلب من Local Inference فقط |
| Reservation غائبة من قراءة واحدة | Quarantine وتحقق بقراءة لاحقة أوOrder Detail | الحذف فورًا |
| انتهت مهلة Calendar Write | اقرأ بالمفتاح الخارجي ثم قرر | إعادة Create عمياء |
| Time Zone أوResource مجهولة | علّمها Unclassified وأوقف Automation | التخمين من خادم التكامل |
أفضل الممارسات
- امنح Reservation Reader نطاق
orders.readفقط. - ضع Tenant Identity في كل Key وLog وCheckpoint.
- احتفظ بـLocal Timestamps الأصلية وحوّل باستخدام IANA Time Zone صريحة.
- استخدم Half-open Intervals باستمرار في Local Conflict Engine.
- احسب
seats_countمقابل السعة بدل عد الصفوف. - عالج Webhooks عبر Durable Idempotent Inbox.
- انشر تغييرات Calendar وERP عبر Outbox مع Read-after-timeout.
- طابق Bounded Windows واعزل Missing Records قبل الإزالة.
- اختبر Day وTime والحدود والسعة وحالات Time Zone.
- اعرض Metrics لعمر Reconciliation والسجلات غير المصنفة وتعارض السعة وOutbox Lag.
Anti-patterns والقيود
- معاملة List Endpoint كقفل حجز أوWrite API.
- استخدام Calendar كسلطة Availability ثانية.
- تجميع Resources بواسطة Title Text مترجم.
- افتراض أن كل Reservation تستهلك مقعدًا واحدًا.
- مقارنة Naive Timestamps في Local Zone الخاصة بالخادم.
- إلغاء طلب تلقائيًا لأن Reconciliation Read واحدة أغفلته.
- إعادة Calendar Create انتهت مهلتها دون البحث عن Event الأولى.
- تسجيل Bearer Tokens أوCustomer Data أوDashboard URLs.
لا يستطيع هذا التصميم اختراع حقول لا يعرضها Provider. إذا لم يتمكن Integration من ربط Reservation بـAuthoritative Capacity Pool، فيمكنه Mirror الحجز ومطابقته، لكنه لا يستطيع إثبات أن الحجز خالٍ من التعارض بصدق.
Checklist التنفيذ
- أكد Authoritative Time Zone للمتجر ومالك Availability.
- اطلب
orders.readفقط للـReservation Reader. - اقرأ Date Window صغيرة وتحقق من أشكال الحقول الموثقة.
- ابن Tenant-scoped Normalized Projection وSource Digest.
- عرّف Resource Mappings وHalf-open Intervals وقواعد Capacity.
- أضف Durable Webhook Inbox وNarrow Refresh Jobs.
- أضف Idempotent Outbox لوجهات Calendar وERP.
- طابق Bounded Lookback وFuture Windows.
- اعزل Missing وUnclassified Records للمراجعة.
- اختبر Retries وDuplicates وUnknown Writes والحدود الزمنية وMulti-seat Overlaps.
اقرأ أيضًا: State Machines لحالات طلبات Salla وZid، وBackfills المتسلسلة لطلبات Salla، وتبديل Salla Webhook Endpoint، ومركز هندسة التجارة الإلكترونية.
المراجع الأساسية
- Salla — List Order Reservations
- Salla — Merchant API changelog
- Salla — Webhooks
- Salla — Register Webhook
- Wikimedia Commons — Computerised Reservation Centre
- Creative Commons — CC0 1.0 Universal
إعداد: Noor Yasser
المراجع الرسمية
تدعم هذه المراجع سلوك الأدوات المذكورة. الأمثلة وقرارات التصميم توضيحية، ويجب تكييفها مع متطلبات المشروع وإصداراته.
إعداد: Noor Yasser
تعمل على تحدٍ تقني مشابه؟
أساعد الفرق على تحويل القرار المعماري إلى نطاق واضح وتنفيذ يمكن تشغيله ومراجعته بثقة.




