المزامنة التزايدية باستخدام updated_since
للاحتفاظ بنسخة من بيانات Sursa في نظامك، لا تحتاج إلى قراءة كل شيء في كل مرة. تقبل قوائم الكائنات التي لها الحقل
updated_at المعامل updated_since، وتعيد فقط الكائنات التي تغيّرت في تلك اللحظة أو بعدها.
curl -G https://api.sursa.com/v1/cards \
-H "Authorization: Bearer $SURSA_API_KEY" \
--data-urlencode "updated_since=2026-10-23T00:00:00Z" \
--data-urlencode "limit=200"مع updated_since تُرتَّب القائمة تصاعديًا حسب updated_at، ثم حسب id، ويتابع المؤشر
بهذا الترتيب. فتقرأ التغييرات بالترتيب الذي حدثت به، ولا تقسمها حدود الصفحات أبدًا بطريقة تُضيع أحدها.
تقبل القوائم التالية المعامل updated_since:
| القائمة | ما يُعد تغييرًا |
|---|---|
GET /v1/cards، GET /v1/cards/count | الحقل updated_at للبطاقة. |
GET /v1/groups | الحقل updated_at لمجموعة المستخدمين: عنوانها أو إعداداتها. |
GET /v1/webhooks | الحقل updated_at لخطاف الويب: إعداداته وسره، لا تسليماته. |
GET /v1/jobs | الحقل updated_at لمهمة المعالجة: كل تغيير في حالتها. |
GET /v1/drafts | الحقل updated_at للمسودة. |
GET /v1/cards/{card_id}/threads | آخر إنشاء أو تعديل للتعليق الأصلي في السلسلة أو لأي رد. وتصل السلسلة كاملة. |
GET /v1/folders، GET /v1/collections/{name}/folders | الحقل updated_at للمجلد. وتصل المجلدات المطابقة قائمةً مسطحة، انظر أدناه. |
ليس للمجموعات والمستخدمين والإعلانات الحقل updated_at، فلا تُصفّى قوائمها به: وهي قصيرة، فاقرأها كاملة في كل
تشغيل. ويجب أن يتضمن الوقت إزاحة المنطقة الزمنية، مثل Z أو +02:00؛ وتُرفض أي قيمة أخرى، كما في
GET /v1/cards.
مع updated_since لا تبقى شجرة المجلدات شجرة: يحمل الحقل folders لكل مجموعة المجلداتِ المتغيرة قائمةً مسطحة،
بحقل children فارغ، ويبيّن الحقل parent_id موضع كل منها. وعندها لا تعيد العملية
GET /v1/folders المجموعات التي لا مجلدات متغيرة فيها.
حلقة المزامنة
- في التشغيل الأول، اقرأ القائمة كاملة بلا
updated_since، واحفظ لحظة بدء التشغيل. - في كل تشغيل تالٍ، مرّر تلك اللحظة المحفوظة في
updated_sinceناقص هامش صغير، دقيقة واحدة مثلًا، واحفظ وقت البدء الجديد. - اكتب كل كائن في مخزنك حسب
id، مستبدلًا النسخة السابقة. والكائنات التي تظهر مرتين بسبب الهامش تُكتب مرة أخرى ببساطة. - اطلب كل صفحة تالية بالمؤشر وبالمعامل
updated_sinceنفسه. فالمؤشر لا يعمل إلا مع عوامل تصفية الصفحة الأولى: بدونها يعيد الطلب الحالة400مع الرمزapi.cursor_invalid.
استخدام وقت بدء التشغيل لا وقت انتهائه يضمن أن التغيير الذي حدث أثناء التشغيل سيلتقطه التشغيل التالي.
تعيد العملية GET /v1/cards مصفوفة JSON، لذا تأتي صفحتها التالية في الترويسة X-Next-Cursor
(انظر القوائم التي تعيد مصفوفة):
const BASE = "https://api.sursa.com";
const headers = { Authorization: `Bearer ${process.env.SURSA_API_KEY}` };
async function syncCards(since, saveCard) {
const startedAt = new Date();
const params = new URLSearchParams({ limit: "200" });
if (since) params.set("updated_since", new Date(since.getTime() - 60_000).toISOString());
let query = params.toString();
while (query) {
const response = await fetch(`${BASE}/v1/cards?${query}`, { headers });
if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`);
for (const card of await response.json()) await saveCard(card); // write into your store by card.id
const cursor = response.headers.get("X-Next-Cursor");
if (cursor) params.set("cursor", cursor); // keep updated_since: the cursor needs the same filters
query = cursor ? params.toString() : "";
}
return startedAt; // pass it as `since` next time
}عمليات الحذف
لا تعيد القائمة إلا الكائنات الموجودة، فلا يمكنها أن تخبرك بأن شيئًا ما حُذف. خذ عمليات الحذف من سجل الأحداث:
curl -G https://api.sursa.com/v1/webhook-events \
-H "Authorization: Bearer $SURSA_API_KEY" \
--data-urlencode "type=card.deleted" \
--data-urlencode "created_since=2026-10-23T00:00:00Z"تتطلب قراءة السجل مفتاحًا بالدور admin والنطاق webhooks:manage. وتُحفظ الأحداث 30 يومًا. فإذا لم تعمل مزامنتك
مدة أطول من ذلك، فاقرأ القائمة كاملة من جديد واحذف من مخزنك كل كائن لم يعد فيها.
يجمع دليل التصدير إلى مستودع البيانات القوائم وupdated_since وسجل الأحداث
في مهمة واحدة.