דלג לתוכן הראשי

Webhooks למפתחים

זמין בתוכניותFreeProResearch

webhook גורם ל-Readsira לשלוח POST של HTTP לשרת שלכם כשמשהו קורה בחשבון, למשל כששומרים סימנייה. הדף הזה מיועד לקוד שמקבל אותו: האירועים, המטען, החתימה וכללי הניסיון החוזר. כדי להוסיף webhook באפליקציה, ראו Webhooks.

לפני שמתחילים​

  • כתובת http או https ציבורית שמקבלת POST. Readsira דוחה localhost וכתובות ברשת פרטית, והיא לא עוקבת אחרי הפניות.
  • השרת שלכם חייב לקרוא את גוף הבקשה הגולמי. אתם צריכים את הבייטים המדויקים כדי לבדוק את החתימה.

איך נראה משלוח​

כל משלוח הוא POST עם גוף JSON ושלוש כותרות:

כותרתערך
content-typeapplication/json
x-readsira-eventשם האירוע, למשל bookmark.created
x-readsira-signaturesha256= ואחריו ה-HMAC של הגוף, בייצוג הקסדצימלי

הגוף הוא מעטפת:

{
"event": "bookmark.created",
"timestamp": "2026-11-04T09:15:02.481Z",
"data": {
"bookmark_id": "c71d0e3a-5b1c-4c58-9d6f-0f6c0d2a9e11",
"user_id": "7b0e1f42-2a43-4f0b-8f0e-1d2c3b4a5f60",
"url": "https://example.com/grid-lab",
"title": "Grid Lab: long-duration storage",
"tags": ["energy"],
"collection_id": "a2c4e6f8-1b3d-4f5a-8c7e-9d0b1a2c3d4e"
}
}

timestamp הוא הרגע ש-Readsira בנתה את המשלוח. הערכים למעלה הם דוגמה.

אירועים​

אתם בוחרים את האירועים לכל webhook. ל-webhook חדש יש bookmark.created.

אירוענשלח כאשרdata
bookmark.createdשומרים סימנייהbookmark_id, user_id, url, title, tags, collection_id
bookmark.updatedמשנים סימנייהbookmarkId, userId, bookmark, changes, notesChanged
bookmark.deletedסימנייה נמחקתbookmarkId, userId, bookmark
bookmark.visitedפותחים סימנייהbookmarkId, userId, visitedAt
output.createdתוצר של פרויקט מסתייםid, projectId, kind, title, version, sourceCount, completedAt

האפליקציה מפרטת גם את collection.created, collection.updated ו-collection.deleted. Readsira עדיין לא שולחת אותם, ולכן webhook שמאזין רק להם לא מקבל דבר.

ב-bookmark.updated וב-bookmark.deleted, bookmark הוא תצלום מצב עם id, url, title, description, collectionId, tags, isStarred, isPublic, domain, notes, triageStatus ו-captureIntent. changes מפרט את שמות השדות שהבקשה קבעה. עבור output.created המטען נושא רק מזהים ומטא-נתונים, אף פעם לא את טקסט התוצר; קראו אותו דרך האפליקציה.

הכפתור בדיקה באפליקציה שולח אירוע נוסף, webhook.test, עם data: { "message": "Test webhook from Readsira", "userId": "..." }. הוא חתום כמו האחרים.

webhooks מושהים כשהחשבון שלכם מתוזמן למחיקה.

בדיקת החתימה​

החתימה מוכיחה שהבקשה הגיעה מ-Readsira ושאיש לא שינה את הגוף. Readsira מחשבת HMAC-SHA256 על הגוף הגולמי, עם הסוד של ה-webhook בתור המפתח, ושולחת את התוצאה כ-sha256= ועוד 64 תווים הקסדצימליים.

הסוד הוא מחרוזת הקסדצימלית בת 64 תווים שהאפליקציה מציגה כשיוצרים את ה-webhook או מחליפים את הסוד שלו. השתמשו במחרוזת הזו כמו שהיא, כטקסט. אל תפענחו אותה מייצוג הקסדצימלי. היא מוצגת פעם אחת.

מקבל ב-Node, בלי חבילות:

import { createHmac, timingSafeEqual } from 'node:crypto';
import { createServer } from 'node:http';

const SECRET = process.env.READSIRA_WEBHOOK_SECRET;

function isFromReadsira(rawBody, signatureHeader) {
const expected = 'sha256=' + createHmac('sha256', SECRET).update(rawBody).digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(signatureHeader ?? '');
return a.length === b.length && timingSafeEqual(a, b);
}

createServer((req, res) => {
const chunks = [];
req.on('data', (chunk) => chunks.push(chunk));
req.on('end', () => {
const rawBody = Buffer.concat(chunks);
if (!isFromReadsira(rawBody, req.headers['x-readsira-signature'])) {
res.writeHead(401).end();
return;
}
const { event, timestamp, data } = JSON.parse(rawBody.toString('utf8'));
console.log(event, timestamp, data);
res.writeHead(204).end();
});
}).listen(3000);

שלושה פרטים שגורמים לרוב הכשלים:

  • חשבו את הגיבוב על הבייטים הגולמיים. אם המסגרת שלכם מפענחת את ה-JSON קודם ואתם מסדרים אותו שוב, הבייטים שונים והבדיקה נכשלת. ב-Express השתמשו ב-express.raw({ type: 'application/json' }) בנתיב ה-webhook.
  • השוו בזמן קבוע, כמו ש-timingSafeEqual עושה, ולא עם ===.
  • אחרי שהחלפתם את הסוד באפליקציה, בקשות שנחתמו עם הסוד הישן נכשלות בבדיקה. עדכנו קודם את READSIRA_WEBHOOK_SECRET.

כדי לדחות הפעלות חוזרות, השוו את timestamp לשעון ודחו משלוחים ישנים יותר מכמה דקות. חותמת הזמן נמצאת בתוך הגוף החתום, ולכן אי אפשר לשנות אותה בלי לשבור את החתימה. ניסיון חוזר (להלן) נושא שוב את האירוע המקורי, לכן ודאו שהמטפל שלכם בטוח להרצה פעמיים.

ענו מהר​

ענו עם כל סטטוס 2xx ברגע ששמרתם את האירוע. Readsira ממתינה 5 שניות וקוראת לכל היותר 64 KB מהתשובה שלכם.

התשובה שלכםמה Readsira עושה
2xxהמשלוח נחשב כמסור.
5xx או אין תשובה בתוך 5 שניותהמשלוח נשלח שוב, עד 4 ניסיונות בסך הכול, עם המתנה ביניהם שמתחילה ב-30 שניות ומוכפלת.
4xxהמשלוח נחשב ככושל ולא נשלח שוב.

האפליקציה מראה לכל webhook כמה פעמים הוא הופעל ומתי הופעל לאחרונה.

טיפים​

  • שמרו על המטפל קצר. העבירו את העבודה לתור וענו קודם.
  • השתמשו בכפתור בדיקה בזמן הפיתוח, לפני ששומרים סימנייה אמיתית.
  • שמרו את הסוד כמו סיסמה. החליפו אותו אם הוא דלף.