Webhooks למפתחים
זמין בתוכניותFreeProResearch
webhook גורם ל-Readsira לשלוח POST של HTTP לשרת שלכם כשמשהו קורה בחשבון, למשל כששומרים סימנייה.
הדף הזה מיועד לקוד שמקבל אותו: האירועים, המטען, החתימה וכללי הניסיון החוזר. כדי להוסיף webhook
באפליקציה, ראו Webhooks.
לפני שמתחילים
- כתובת
httpאוhttpsציבורית שמקבלתPOST. Readsira דוחהlocalhostוכתובות ברשת פרטית, והיא לא עוקבת אחרי הפניות. - השרת שלכם חייב לקרוא את גוף הבקשה הגולמי. אתם צריכים את הבייטים המדויקים כדי לבדוק את החתימה.
איך נראה משלוח
כל משלוח הוא POST עם גוף JSON ושלוש כותרות:
| כותרת | ערך |
|---|---|
content-type | application/json |
x-readsira-event | שם האירוע, למשל bookmark.created |
x-readsira-signature | sha256= ואחריו ה-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 כמה פעמים הוא הופעל ומתי הופעל לאחרונה.
טיפים
- שמרו על המטפל קצר. העבירו את העבודה לתור וענו קודם.
- השתמשו בכפתור בדיקה בזמן הפיתוח, לפני ששומרים סימנייה אמיתית.
- שמרו את הסוד כמו סיסמה. החליפו אותו אם הוא דלף.
קשור
- Webhooks (הגדרה באפליקציה)
- דוגמאות
- מגבלות קצב ושגיאות