VellumUp
תמחורבלוגאינטגרציות
התחברותהרשמה
חזרה לתיעוד

בעמוד זה

כל האינטגרציות

WordpressShopifyWebflowWixWebhooks
חזרה לתיעוד

Events · HTTP POST

Webhooks

מסירת מאמרים מיידית לשרת שלך — ללא polling, ללא מפתחות API.

איך זה עובד

מסירת מאמרים מיידית לשרת שלך — ללא polling, ללא מפתחות API.

1

הוסף את כתובת ה-HTTPS שלך למטה. VellumUp ישלח POST אליה בכל פעם שאירוע יתרחש.

2

כל משלוח חתום עם HMAC-SHA256. אמת את הכותרת X-VellumUp-Signature כדי לוודא שהגיע מאיתנו.

3

פרסר את ה-JSON, שמור את המאמר במסד הנתונים שלך, הפעל rebuild, או עשה כל מה שתרצה.

אירועים

נקודת הקצה שלך מקבלת אחד מהאירועים הבאים בכל משלוח — קרא את הכותרת X-VellumUp-Event כדי לנתב בהתאם

article.published

מופעל כאשר מאמר חדש נוצר, או כאשר סטטוס המאמר משתנה ל-published

article.unpublished

מופעל כאשר מאמר מועבר חזרה לסטטוס טיוטה

article.updated

מופעל כאשר כותרת, תוכן, מילות מפתח או תמונת נושא של מאמר נערכים ונשמרים

article.translated

מופעל בכל פעם שתרגום לשפה נשמר — כולל שדות language_code ו-language_name באובייקט ה-data

מבנה ה-Payload

כל משלוח מכיל את המאמר המלא במצבו הנוכחי. כל האירועים חולקים את אותם השדות — רק article.translated מוסיף language_code ו-language_name.

השתמש בשדה slug לבניית כתובת המאמר באתר שלך. הוא בטוח ל-URL, ייחודי לכל דומיין, ויציב גם לאחר עדכונים.
שדהסוגתיאור
idstring (UUID)מזהה ייחודי של המאמר בחשבונך
slugstringמזהה ידידותי ל-URL — השתמש בו לבניית כתובת המאמר (לדוגמה yourblog.com/blog/slug)
titlestringכותרת המאמר המלאה
contentstringגוף המאמר המלא. מרקדאון כברירת מחדל — או HTML אם בחרת בפורמט HTML בעת יצירת נקודת הקצה
cover_imagestring | nullכתובת תמונת הנושא שנוצרה על ידי AI, או null אם הדילוג על יצירת תמונה
cover_image_urlstring | nullSame as cover_image (explicit naming for clarity)
meta_descriptionstring | nullתיאור מטא לקידום אתרים, עד 160 תווים
focus_keywordstring | nullמילת מפתח ראשית שהמאמר מכוון אליה
secondary_keywordsstring[]מילות מפתח תומכות הכלולות בתוכן
key_takeaways{ takeaway, _heading? }[]מערך של אובייקטי key takeaway. לכל אחד יש שדה takeaway. הפריט הראשון כולל גם _heading — כותרת הסעקשן מתורגמת לשפת המאמר (למשל Key Takeaways, נקודות מפתח). השתמש ב-_heading להצגת כותרת הbox בשפה הנכונה.
word_countnumberספירת מילים משוערת של התוכן
reading_time_minutesnumberEstimated reading time in minutes (word_count ÷ 200)
website_urlstring | nullכתובת URL מלאה של האתר המחובר
website_domainstringדומיין האתר המחובר (לדוגמה yourblog.com)
status"published" | "draft"סטטוס המאמר הנוכחי
internal_link_slugsstring[]Slugs of internal links the AI placed in this article — use these to show "Related Articles" on your site
og_titlestringArticle title for social sharing & OG tags
og_descriptionstringMeta description (fallback to first 155 chars)
og_type"article"Content type for Open Graph metadata
created_atstring (ISO 8601)מתי המאמר נוצר לראשונה
updated_atstring (ISO 8601)מתי המאמר עודכן לאחרונה
language_codestring (BCP-47)רק ב-article.translated — קוד BCP-47 לדוגמה "fr", "es", "he"
language_namestringרק ב-article.translated — שם השפה קריא לאנשים, לדוגמה "French"

דוגמת payload

json
{
  "id":         "del_a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "created_at": "2026-04-22T10:30:00.000Z",

  "data": {
    "id":                  "f7e6d5c4-b3a2-1098-fedc-ba9876543210",
    "slug":                "how-to-improve-your-seo-in-2026",
    "title":               "How to Improve Your SEO in 2026",
    "content":             "# How to Improve Your SEO in 2026\n\nSearch engine optimization has evolved...",
    "cover_image":         "https://storage.supabase.co/article-images/user123/ai/hero_abc123.jpg",
    "cover_image_url":     "https://storage.supabase.co/article-images/user123/ai/hero_abc123.jpg",
    "meta_description":    "Learn proven SEO strategies for 2026. From technical optimization to content strategy.",
    "focus_keyword":       "improve SEO 2026",
    "secondary_keywords":  ["on-page SEO", "SEO tips", "search ranking", "technical SEO"],
    "key_takeaways": [
      { "takeaway": "Technical SEO fixes (Core Web Vitals, indexability) deliver the fastest ranking gains.", "_heading": "Key Takeaways" },
      { "takeaway": "Content that matches search intent outperforms keyword-stuffed pages every time." },
      { "takeaway": "Building authoritative backlinks remains the most powerful off-page SEO signal." }
    ],
    "word_count":           1840,
    "reading_time_minutes": 9,
    "internal_link_slugs":  ["technical-seo-checklist", "on-page-seo-guide", "keyword-research-tools"],
    "website_url":          "https://yourblog.com",
    "website_domain":       "yourblog.com",
    "status":               "published",
    "og_title":             "How to Improve Your SEO in 2026",
    "og_description":       "Learn proven SEO strategies for 2026. From technical optimization to content strategy.",
    "og_type":              "article",
    "created_at":           "2026-04-22T10:30:00.000Z",
    "updated_at":           "2026-04-22T10:30:00.000Z"
  }
}

אימות בקשות Webhook

איך החתימה עובדת

כל משלוח כולל את הכותרת X-VellumUp-Signature בפורמט t=TIMESTAMP,v1=SHA256_HEX. לאימות: שרשר את ה-timestamp וגוף הבקשה הגולמי כ-"TIMESTAMP.RAW_BODY", חשב HMAC-SHA256 עם סוד החתימה שלך, והשווה עם v1 באמצעות פונקציה בזמן קבוע. תמיד השתמש בגוף הגולמי — לא JSON מפורסר.

HMAC-SHA256(whsec_secret, "<timestamp>.<raw_json_body>")// X-VellumUp-Signature: t=<ts>,v1=<hex>

אימות חתימה — דוגמאות קוד

const crypto = require('crypto');

const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET; // whsec_...

function verifySignature(rawBody, sigHeader, secret) {
  if (!sigHeader) return false;

  // Parse "t=<timestamp>,v1=<hmac>"
  const parts = Object.fromEntries(sigHeader.split(',').map(p => p.split('=')));
  const { t: ts, v1: received } = parts;
  if (!ts || !received) return false;

  // Reject requests older than 5 minutes
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;

  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${ts}.${rawBody}`)
    .digest('hex');

  return crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected));
}

טיפול ב-Payload של ה-Webhook

מטפלים מלאים — אמת את החתימה, הגב 200 מיידית, ואז עבד את נתוני המאמר ברקע.

// app/api/webhook/route.ts
import { NextRequest } from 'next/server';
import { createHmac, timingSafeEqual } from 'crypto';

const SECRET = process.env.WEBHOOK_SECRET!;

function verify(rawBody: string, sig: string): boolean {
  const parts = Object.fromEntries(sig.split(',').map(p => p.split('=')));
  const { t: ts, v1 } = parts;
  if (!ts || !v1) return false;
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
  const expected = createHmac('sha256', SECRET)
    .update(`${ts}.${rawBody}`)
    .digest('hex');
  try {
    return timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
  } catch { return false; }
}

export async function POST(req: NextRequest) {
  const rawBody = await req.text();
  const sig     = req.headers.get('x-vellumup-signature') ?? '';
  const event   = req.headers.get('x-vellumup-event') ?? '';

  if (!verify(rawBody, sig)) {
    return new Response('Unauthorized', { status: 401 });
  }

  const { data } = JSON.parse(rawBody);

  if (event === 'article.published') {
    // Save to your database
    // await db.articles.upsert({ where: { slug: data.slug }, ... })
    console.log('New article:', data.title, '→', data.slug);
  }
  if (event === 'article.translated') {
    // Save translation
    console.log(`[${data.language_code}] ${data.title}`);
  }
  if (event === 'article.updated') {
    // Update existing article
    console.log('Updated:', data.title);
  }

  return new Response('OK', { status: 200 });
}

מקרי שימוש

סנכרון למסד נתונים או CMS

שמור מאמרים נכנסים ישירות למסד הנתונים או ל-CMS ללא ראש שלך ברגע שהם נוצרים — ללא ייצוא ידני.

javascript
// Upsert article into your database on publish
if (event === 'article.published') {
  await db.articles.upsert({
    where:  { slug: data.slug },
    update: { title: data.title, content: data.content, updatedAt: new Date() },
    create: { slug: data.slug, title: data.title, content: data.content },
  });
}

הפעלת בנייה מחדש של האתר

קרא ל-deploy hook של ספק האירוח שלך (Vercel, Netlify וכו') לבניית האתר הסטטי שלך מחדש בכל פעם שמאמר חדש מגיע.

javascript
// Trigger a Vercel rebuild after publish
if (event === 'article.published') {
  await fetch(process.env.VERCEL_DEPLOY_HOOK_URL, { method: 'POST' });
}

// Or for Netlify:
if (event === 'article.published') {
  await fetch(process.env.NETLIFY_BUILD_HOOK, { method: 'POST' });
}

סנכרון תוכן רב-לשוני

האזן לאירועי article.translated כדי לסנכרן אוטומטית גרסאות מתורגמות לדפי ה-locale המתאימים באתר שלך.

javascript
// Save translations to the correct locale path
if (event === 'article.translated') {
  await db.translations.upsert({
    where:  { slug_locale: { slug: data.slug, locale: data.language_code } },
    update: { title: data.title, content: data.content },
    create: { slug: data.slug, locale: data.language_code,
              title: data.title, content: data.content },
  });
}

שליחת התראות

פרסם ב-Slack, שלח אימייל, או דחף התראה לצוות שלך בכל פעם שמאמר חדש מתפרסם או מתעדכן.

javascript
// Post a Slack notification when a new article is published
if (event === 'article.published') {
  await fetch(process.env.SLACK_WEBHOOK_URL, {
    method:  'POST',
    headers: { 'Content-Type': 'application/json' },
    body:    JSON.stringify({
      text: `📝 New article published: *${data.title}*
${data.website_url}/${data.slug}`,
    }),
  });
}

הצגת מאמרים ב-React

VellumUp מעביר את תוכן המאמר כ-Markdown. השתמש בחבילת react-markdown להצגתו באפליקציית React שלך — היא מטפלת כותרות, קישורים, בלוקי קוד ורשימות אוטומטית.
typescript
// 1. Install react-markdown
// npm install react-markdown

// 2. components/Article.tsx
import ReactMarkdown from 'react-markdown';

interface Article {
  title:        string;
  content:      string;  // raw Markdown from webhook
  slug:         string;
  cover_image?: string | null;
}

export function Article({ article }: { article: Article }) {
  return (
    <article>
      {article.cover_image && (
        <img src={article.cover_image} alt={article.title} />
      )}
      <h1>{article.title}</h1>
      <div className="prose">
        <ReactMarkdown>{article.content}</ReactMarkdown>
      </div>
    </article>
  );
}

// 3. With syntax highlighting (optional)
// npm install react-markdown remark-gfm rehype-highlight

import ReactMarkdown    from 'react-markdown';
import remarkGfm        from 'remark-gfm';
import rehypeHighlight  from 'rehype-highlight';

<ReactMarkdown
  remarkPlugins={[remarkGfm]}
  rehypePlugins={[rehypeHighlight]}
>
  {article.content}
</ReactMarkdown>

פתרון בעיות

אימות החתימה נכשל

ודא שאתה משתמש בגוף הבקשה הגולמי — לפני כל פרסור JSON. frameworks רבים מפרסרים את הגוף אוטומטית; הגדר אותם להעביר בתים גולמיים למסלול ה-webhook שלך.

קבלת משלוחים כפולים

VellumUp עשוי לנסות שוב משלוחים שנכשלו. הפוך את המטפל שלך לאידמפוטנטי על ידי בדיקת ה-slug לפני הכנסה, או השתמש באילוץ ייחודי על עמודת ה-slug.

נקודת הקצה מסיימת בזמן קצוב (המשלוח מסומן כנכשל)

VellumUp מחכה עד 8 שניות לתגובה. הגב עם HTTP 200 מיידית, ואז עבד את ה-payload באופן אסינכרוני בעבודת רקע או תור.

שדות null ב-payload

שדות כמו cover_image, meta_description ו-focus_keyword יכולים להיות null. תמיד טפל בערכי null במפורש בקוד שלך במקום להניח שהם קיימים.

משלוח הבדיקה מצליח אך משלוחים אמיתיים נכשלים

אירועי בדיקה משתמשים ב-payload פשוט יותר. ודא שהמטפל שלך מטפל בכל סוגי האירועים (article.published, article.updated, article.translated) ולא קורס על שדות בלתי צפויים.

שיטות עבודה מומלצות לאבטחה

תמיד אמת את החתימה

אל תעבד payload ללא אימות חתימת HMAC-SHA256. זה מבטיח שהבקשה הגיעה מ-VellumUp ולא שונתה.

דחה timestamps ישנים

השלך כל בקשה שבה |now − timestamp| > 300 שניות. זה מונע התקפות replay שבהן תוקף שולח מחדש בקשה תקינה שנלכדה.

השתמש בגוף הבקשה הגולמי

חתום על הבתים הגולמיים כפי שהתקבלו — לפני כל פרסור JSON. פרסור וסריאליזציה מחדש עלולים לשנות רווחים ולשבור את בדיקת החתימה.

הגב מהר, עבד בצורה אסינכרונית

החזר HTTP 200 תוך מספר שניות, אחרת VellumUp יסמן את המשלוח כנכשל. העבר עיבוד כבד לתור ברקע.

אינטגרציות
VellumUp

מאמרי SEO מבוססי AI שמתאימים לקול המותג שלך ומדורגים גבוה.

דברו איתנו

support@vellumup.com

© 2026 VellumUp. כל הזכויות שמורות.

תנאי שירות·מדיניות פרטיות·נגישות