مزامنة نظامك عبر مصدر مخصص
يربط المصدر المخصص نظامًا ليس له موصّل مدمج: الويكي لديك، أو أداة التذاكر، أو قاعدة بيانات، أو تصديرًا من أي مكان. ترسل شيفرتك المستندات إلى Sursa، فيحوّلها Sursa إلى بطاقات في المجموعة والمجلدات التي ضُبط المصدر لها، مع البحث والإجابات والتوثيق والصلاحيات نفسها التي لبطاقات أي مصدر آخر.
وبخلاف كتابة البطاقات مباشرة، يتتبع المصدر المخصص ما أرسلته. ففي نهاية المزامنة الكاملة، يؤرشف Sursa كل مستند لم ترسله، فتصل عمليات الحذف في نظامك إلى Sursa بلا عمل إضافي.
إعداد المصدر
ينشئ المشرف المصدر في Sursa من Sources → New source → Custom source (المصادر ← مصدر جديد ← مصدر مخصص)، ويختار:
- المجموعة، ومجلدًا لبطاقاتها إن شاء؛
- وضع المجلدات: كل البطاقات في المجلد المختار، أو مجلدات فرعية تعكس
pathكل مستند؛ - الصلاحيات: صلاحيات المجموعة، أو «كما في المصدر»، حيث يذكر كل مستند من يحق له رؤيته.
تعرض صفحة المصدر معرّفه، والأمثلة تستخدم 42.
اختيار المفتاح
| المفتاح | البادئة | ما يستطيعه |
|---|---|---|
| مفتاح المصدر | kbsrc_ | كتابة المستندات في هذا المصدر الواحد. ولا شيء غير ذلك: لا يستطيع القراءة ولا البحث. أنشئه في صفحة المصدر من API keys (مفاتيح API للمصدر). |
مفتاح المؤسسة ذو النطاق import:write | kb_ | الكتابة في أي مصدر مخصص للمؤسسة وقراءة حالته. ويتطلب إنشاء مصدر ومفاتيحه النطاق admin. |
مفتاح المصدر هو الخيار الأكثر أمانًا لتكامل واحد، ولا سيما إذا كان يعمل على منصة طرف ثالث. أما مفتاح المؤسسة ذو
النطاق import:write فيناسب خدمة تغذي عدة مصادر.
يُرسَل المفتاحان بالطريقة نفسها، وكل نقاط نهاية الإرسال تقع تحت /v1/push/sources/{source_id}. تحقّق من المفتاح ومن
حالة المصدر بالعملية GET /v1/push/sources/{source_id}:
curl https://api.sursa.com/v1/push/sources/42 \
-H "Authorization: Bearer $SURSA_SOURCE_KEY"{"source_id": 42, "name": "Helpdesk articles", "documents": 1840, "open_sync": null}
المستند
| الحقل | مطلوب | الوصف |
|---|---|---|
external_id | نعم | معرّفك الثابت للمستند، حتى 512 حرفًا. وإرسال المعرّف نفسه مرة أخرى يستبدل المستند. |
title | نعم | عنوان البطاقة، حتى 500 حرف. وللملف، اسم الملف افتراضيًا. |
content | نعم، ما لم يكن هناك ملف | حتى 5 ميغابايت. |
content_type | لا | إحدى القيم html (افتراضي) أو markdown أو text. ويُنظَّف HTML من النصوص البرمجية والأنماط والاستمارات والكائنات المدمجة. |
url | لا | رابط المستند في نظامك، يُعرض على البطاقة. |
path | لا | المجلدات، على شكل مصفوفة (["Support", "Billing"]) أو سلسلة نصية ("Support/Billing")، حتى 10 مستويات. |
permissions | لا | القيمة {"everyone": true}، أو {"emails": [...], "groups": [...]}. تُستخدم حين تكون صلاحيات المصدر «كما في المصدر». |
tags | لا | حتى 50 وسمًا، تُضاف إلى وسوم المصدر. |
author_email | لا | إذا كان مستخدمًا في المؤسسة، يصبح المسؤول عن البطاقة. |
updated_at | لا | وقت تغيّر المستند في نظامك (RFC 3339). |
metadata | لا | أزواج المفتاح والقيمة الخاصة بك على البطاقة. انظر البيانات الوصفية. |
category | لا | فئة البطاقة: مفتاح فئة من فئات المؤسسة. |
verifiers، verify_interval_days | لا | من يوثّق البطاقة (مستخدمون بالبريد الإلكتروني ومجموعات مستخدمين) وكل كم يومًا. |
upload_id | لا | ملف المستند من الرفع على أجزاء، بدل content. |
attachments | لا | حتى 20 ملفًا إضافيًا للمستند، على شكل قائمة من upload_id. ويصبح كل منها بطاقة مستقلة في المصدر. |
بدل content، يمكن أن يحمل مستند واحد ملفًا حتى 100 ميغابايت في طلب multipart/form-data: الملف في الجزء file،
والحقول أعلاه بصيغة JSON في الجزء document. وتُنشأ عمليات الرفع على أجزاء الخاصة بالحقلين upload_id
وattachments بمفتاح مؤسسة له النطاق import:write والغرض import_attachment؛ ولا يستطيع مفتاح المصدر إنشاءها.
طريقتان للإرسال
التحديثات المباشرة تناسب الأنظمة التي تخبرك بكل تغيير، مثل خطاف ويب من نظام الدعم لديك أو خطوة في Zapier. أرسل المستند حين يُنشأ أو يتغيّر، واحذفه حين يُزال:
| الطلب | ما يفعله |
|---|---|
POST /v1/push/sources/{source_id}/documents | ينشئ مستندًا واحدًا أو يستبدله. |
POST /v1/push/sources/{source_id}/documents/batch | ينشئ مستندات كثيرة أو يستبدلها معًا. |
DELETE /v1/push/sources/{source_id}/documents/{external_id} | يزيل مستندًا واحدًا. طبّق ترميز URL على المعرّف. |
تصبح التغييرات بطاقات خلال دقيقة تقريبًا، وتُعالَج التغييرات المتتالية معًا.
المزامنات تناسب التصديرات الدورية: ترسل كل شيء، أو كل ما تغيّر، ويُجري Sursa المطابقة. وبقية هذا الدليل عن المزامنات.
تشغيل مزامنة كاملة
للمزامنة ثلاث خطوات: الفتح، والإرسال، والإغلاق.
1. افتح
تفتح العملية POST /v1/push/sources/{source_id}/syncs مزامنة وتعيد رقمها:
curl -X POST https://api.sursa.com/v1/push/sources/42/syncs \
-H "Authorization: Bearer $SURSA_SOURCE_KEY" \
-H "Idempotency-Key: sync-2026-10-24" \
-H "Content-Type: application/json" \
-d '{"type": "initial", "max_minutes": 180}'{"sync_number": 7, "type": "initial", "status": "open", "opened_at": "2026-10-24T02:00:00Z",
"expires_at": "2026-10-24T05:00:00Z", "pushed": 0, "removed": 0}
- قيمة
typeهيinitialلأول مزامنة للمصدر، وincrementalبعد اكتمال مزامنة. والمزامنةincrementalقبل أي مزامنة مكتملة تعيدsources.push_initial_required. - لا يمكن أن تُفتح إلا مزامنة واحدة في كل مرة: والثانية تعيد الحالة
409مع الرمزsources.push_sync_open. - تبقى المزامنة مفتوحة مدة
max_minutes(60 افتراضيًا، وحتى 1440). وبعدها تنتهي صلاحيتها: لا يُؤرشف شيء، ولا يعود رقمها مقبولًا. اختر مدة أطول بهامش مريح من مدة التصدير لديك.
2. أرسل المستندات
أرسل المستندات في دفعات يصل حجم كل منها إلى 500 مستند، مع رقم المزامنة. ويصل نص الدفعة إلى 50 ميبيبايت؛
والملفات داخل الدفعة تُمرَّر على شكل upload_id.
curl -X POST https://api.sursa.com/v1/push/sources/42/documents/batch \
-H "Authorization: Bearer $SURSA_SOURCE_KEY" \
-H "Idempotency-Key: sync-7-batch-1" \
-H "Content-Type: application/json" \
-d '{
"sync_number": 7,
"documents": [
{"external_id": "faq-shipping", "title": "Shipping", "content_type": "markdown",
"content": "# Shipping\n\nWe ship worldwide within 5 days.", "path": ["Support"]},
{"external_id": "faq-refunds", "title": "Refunds", "content_type": "html",
"content": "<p>Refunds take 14 days.</p>", "path": ["Support", "Billing"],
"permissions": {"groups": ["Support"]}, "metadata": {"article_id": "1042"}}
]
}'تحتوي الاستجابة نتيجة لكل مستند، بالترتيب الذي أرسلتها به:
{
"results": [
{"external_id": "faq-shipping", "result": "unchanged", "status": "indexed", "card_id": "8c1d…", "version": "5e0f…"},
{"external_id": "faq-refunds", "result": "updated", "status": "pending", "card_id": "3f2c…", "version": "a91b…"}
]
}
| الحقل | المعنى |
|---|---|
result | ما حدث للمستند الآن: created، أو updated، أو unchanged، أو deleted، أو not_found، أو error، أو skipped (في دفعة ذرية لم تُطبَّق). |
status | أين وصل المستند في طريقه إلى بطاقة: pending، أو processing (كُتبت البطاقة وتجري فهرستها)، أو indexed، أو failed، أو removed. |
card_id | بطاقة المستند، بمجرد وجودها. |
version | قيمة تجزئة للمحتوى والحقول. والمستند نفسه المرسل مرة أخرى له الإصدار نفسه ويكون unchanged. |
error، reason | سبب فشل المستند. والحقل reason رمز ثابت: content_invalid، أو file_rejected، أو too_large، أو limit_reached، أو index_failed، أو batch_rejected (فشل مستند آخر في دفعة ذرية). |
افتراضيًا، يُطبَّق كل مستند في الدفعة وحده: المستند المعيب الواحد لا يوقف البقية.
لا يلزم إرسال المستندات التي لم تتغيّر منذ آخر مزامنة مرة أخرى. أكّدها بمعرّفاتها بالعملية
POST /v1/push/sources/{source_id}/syncs/{sync_number}/touch، حتى 1000
معرّف في الطلب الواحد، كي تُبقي عليها المطابقة الكاملة:
curl -X POST https://api.sursa.com/v1/push/sources/42/syncs/7/touch \
-H "Authorization: Bearer $SURSA_SOURCE_KEY" \
-H "Content-Type: application/json" \
-d '{"external_ids": ["faq-contact", "faq-hours"]}'3. أغلق
تنهي العملية POST /v1/push/sources/{source_id}/syncs/{sync_number}/close
المزامنة:
curl -X POST https://api.sursa.com/v1/push/sources/42/syncs/7/close \
-H "Authorization: Bearer $SURSA_SOURCE_KEY" \
-H "Content-Type: application/json" \
-d '{"status": "complete"}'status | الأثر |
|---|---|
complete | مطابقة كاملة. يُؤرشف كل مستند في المصدر لم يُرسَل ولم يُؤكَّد في هذه المزامنة. لا تستخدمها إلا إذا أرسلت كل شيء. |
complete_incremental | يطبّق ما أرسلته ولا يؤرشف شيئًا. |
failed | لا يؤرشف شيئًا، ويُبقي ما أُرسل من قبل. أضف reason (مثل API_ERROR) وerror_details للسجل. |
أغلق بالقيمة failed كلما توقف التصدير لديك في منتصفه: فالقيمة complete بعد تصدير جزئي ستؤرشف كل مستند لم تصل
إليه. وتكرار الإغلاق نفسه يعيد النتيجة نفسها.
بعد الإغلاق، يحوّل Sursa المستندات إلى بطاقات خلال دقيقة تقريبًا. وتعرض صفحة المصدر كل مزامنة مع عدد المستندات
المرسلة والمؤرشفة، وتعيد العملية GET /v1/push/sources/{source_id}/syncs/{sync_number}
العدادات نفسها.
المزامنات التزايدية
بين المزامنات الكاملة، أرسل ما تغيّر فقط:
- افتح مع
"type": "incremental". - أرسل المستندات المتغيرة، وضع معرّفات المحذوفة في
deletes(أدناه). - أغلق بالقيمة
complete_incremental.
شغّل مزامنة كاملة من حين لآخر، أسبوعيًا مثلًا، لالتقاط ما فات المزامنة التزايدية.
حذف المستندات في دفعة
يمكن للدفعة أن تزيل مستندات مع المستندات التي تكتبها. اسرد معرّفاتها في deletes:
{
"sync_number": 8,
"documents": [{"external_id": "faq-shipping", "title": "Shipping", "content": "…"}],
"deletes": ["faq-old-returns", "faq-fax"]
}
لكل معرّف محذوف إدخاله الخاص في results، بقيمة result هي deleted، أو not_found إن لم يكن في المصدر مستند
كهذا. وحذف المعرّف نفسه مرة أخرى لا ضرر منه.
الدفعات الذرية
بعض التغييرات لا معنى لها إلا معًا، مثل مستند والمستند الذي يحل محله. أرسل "atomic": true، فتُطبَّق الدفعة
كاملة أو لا تُطبَّق إطلاقًا: إذا فشل أي مستند في فحوصه، لا يُطبَّق شيء من الدفعة، وتكون الاستجابة 422 مع الرمز
sources.push_batch_rejected ونتيجة كل مستند في الحقل error.details.results: للمستندات التي فشلت الحقل error،
ولغيرها النتيجة skipped.
{"sync_number": 8, "atomic": true, "documents": […], "deletes": ["faq-old-returns"]}
بلا atomic، تُطبَّق الدفعة مستندًا تلو مستند. استخدم الدفعات الذرية للتغييرات المترابطة، والدفعات العادية
للتعبئات الجماعية، حيث لا ينبغي أن يعطّل مستند معيب واحد البقية.
التحقق من نتيجة كل مستند
تخبرك استجابة الدفعة بكيفية كتابة كل مستند. أما تحويله إلى بطاقة فيجري بعد ذلك، لذا قد تبقى قيمة status هي
pending. للعثور على مستندات مزامنة لم تصبح بطاقات:
curl "https://api.sursa.com/v1/push/sources/42/syncs/7/documents?status=failed" \
-H "Authorization: Bearer $SURSA_SOURCE_KEY"لكل إدخال الحقول external_id، وtitle، وstatus، وcard_id، وversion، وreason، وتُقسَّم القائمة إلى صفحات
بالمعامل cursor. ويقبل المعامل status أيضًا القيم pending، وprocessing، وindexed، وremoved.
ويمكنك أيضًا أن تتلقى الخبر بدل أن تسأل: يصل الحدثان import.sync_completed (أُغلقت مزامنة وعولجت، مع مجاميعها)
وimport.document_failed (لم يصبح مستند بطاقة، مع reason) عبر خطاف الويب وفي
سجل الأحداث.
إعادة المحاولة
- أرسل
Idempotency-Keyمع كل طلبPOST. والدفعة المكررة بالمفتاح نفسه تعيد النتيجة الأولى. - حتى بلا المفتاح، لا يصبح المستند ذو قيمة
external_idنفسها بطاقة ثانية أبدًا: فهوunchangedأوupdated. - إذا توقفت عملية التشغيل لديك في منتصف مزامنة، فافتح مزامنة جديدة بعد انتهاء صلاحية القديمة، أو أغلق القديمة
بالقيمة
failedإن كان رقمها لا يزال لديك، ثم شغّل المزامنة من جديد.
الحدود
| الحد | القيمة |
|---|---|
| محتوى المستند الواحد | 5 ميغابايت |
| الملف في طلب المستند الواحد | 100 ميغابايت |
| المستندات في الدفعة | 500 |
| نص طلب الدفعة | 50 ميبيبايت |
المعرّفات في طلب touch | 1000 |
| المستندات في المصدر | بحسب الخطة: من 100,000 |
| المزامنة المفتوحة | 60 دقيقة افتراضيًا، وحتى 24 ساعة |
المستند الذي يتجاوز حد المستندات في المصدر يفشل بالسبب limit_reached في الدفعة؛ أما طلب المستند الواحد فيجيب
بالحالة 409 مع الرمز sources.push_too_many_documents. وتسري حدود
المعدل كما في أي طلب آخر؛ انظر
حدود معدل الطلبات والحصص.
الأخطاء الشائعة
| الاستجابة | السبب | ما العمل |
|---|---|---|
401 sources.push_key_invalid | المفتاح خاطئ أو مُبطَل أو يخص مصدرًا آخر. | تحقّق من المفتاح ومن معرّف المصدر في المسار. |
400 sources.push_document_invalid | حقل مطلوب ناقص أو تجاوز لأحد الحدود. | أصلح المستند؛ في الدفعة العادية لا يفشل إلا ذلك المستند. |
409 sources.push_sync_open | مزامنة أخرى لا تزال مفتوحة. | أغلقها، أو انتظر حتى تنتهي صلاحيتها. |
409 sources.push_sync_closed | المزامنة مغلقة أو انتهت صلاحيتها. | افتح مزامنة جديدة؛ وارفع max_minutes للتصديرات الطويلة. |
403 sources.feature_disabled | المصادر ليست جزءًا من خطة المؤسسة. | تواصل مع المشرف. |
429 | طلبات كثيرة جدًا. | انتظر Retry-After؛ وأرسل دفعات أقل عددًا وأكبر حجمًا. |