אוטומציה של משימות נפוצות במרכז העזרה בעזרת ממשק ה-API Notiondesk

דוגמאות ל-API של Notiondesk: סנכרון מפעולות GitHub, גיבוי מאמרים כ-markdown, פרסום משוב ב-Slack ודיווח על חיפושים ללא תוצאות.

4 דקות קריאה

מאמר זה אוסף סקריפטים מוכנים לשימוש של Notiondesk API עבור המשימות שצוותי מטמיעים באופן אוטומטי: פרסום עריכות של Notion מתוך צינור CI, גיבוי כל מאמר כ-markdown, שליחת משוב שלילי ל-Slack, דיווח על החיפושים שמרכז העזרה שלך אינו יכול לענות עליהם, מציאת סנכרונים כושלים ויישום מותג אחד על מספר מרכזי עזרה. העתק מתכון, קבע שני משתני סביבה והפעל אותו.

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

  • הגדר את שניהם כמשתני סביבה:
export NOTIONDESK_API_KEY="nd_wsk_..."
export NOTIONDESK_SITE_ID="c74781f6-1aea-4e17-ab23-bbb8b4d174b6"

מתכוני ה-JavaScript דורשים Node.js גרסה 18 ואילך.

עוזר משותף קטן

שמור קובץ זה בשם notiondesk.mjs ליד הסקריפטים שלך. הוא שולח את הכותרות, ממתין עד שה-API עונה ל-429 rate_limited, וקורא כל עמוד ברשימה.

סנכרן את מרכז העזרה שלך מ-GitHub Actions

היקף: sync

פרסמו את העריכות שלכם ב-Notion מתהליך עבודה של GitHub Actions, לדוגמה מיד לאחר שחרור. אחסן את המפתח כסוד המאגר NOTIONDESK_API_KEY ואת מזהה מרכז העזרה כמשתנה המאגר NOTIONDESK_SITE_ID.

export const SITE_ID = process.env.NOTIONDESK_SITE_ID;

export async function api(path, options = {}) {
  for (let attempt = 0; attempt < 5; attempt++) {
    const response = await fetch(`https://api.notiondesk.so${path}`, {
      ...options,
      headers: {
        Authorization: `Bearer ${process.env.NOTIONDESK_API_KEY}`,
        "nd-version": "2026-10-16",
        ...options.headers,
      },
    });

    if (response.status === 429) {
      const seconds = Number(response.headers.get("Retry-After")) || 5;
      await new Promise((resolve) => setTimeout(resolve, seconds * 1000));
      continue;
    }
    if (!response.ok) {
      throw new Error(`${response.status} ${await response.text()}`);
    }
    return response.status === 204 ? null : response.json();
  }
  throw new Error(`Still rate limited on ${path}`);
}

export async function listAll(path) {
  const items = [];
  let cursor = null;
  do {
    const url = new URL(`https://api.notiondesk.so${path}`);
    url.searchParams.set("page_size", "100");
    if (cursor) {
      url.searchParams.set("cursor", cursor);
    }
    const page = await api(`${url.pathname}${url.search}`);
    items.push(...page.data);
    cursor = page.has_more ? page.next_cursor : null;
  } while (cursor);
  return items;
}
name: Sync help center
on:
  workflow_dispatch:
  release:
    types: [published]

jobs:
  sync:
    runs-on: ubuntu-latest
    steps:
      - name: Trigger a Notiondesk sync
        run: |
          status=$(curl -s -o response.json -w "%{http_code}" -X POST \
            "https://api.notiondesk.so/sites/${{ vars.NOTIONDESK_SITE_ID }}/sync" \
            -H "Authorization: Bearer ${{ secrets.NOTIONDESK_API_KEY }}" \
            -H "nd-version: 2026-10-16" \
            -H "Idempotency-Key: github-${{ github.run_id }}-${{ github.run_attempt }}")
          if [ "$status" = "409" ]; then echo "A sync is already running."; exit 0; fi
          if [ "$status" != "204" ]; then cat response.json; exit 1; fi
          echo "Sync queued."
  • 204 פירושו שהסנכרון נמצא בתור. הוא פועל ברקע.
  • 409 conflict_error פירושו שסנכרון של מרכז העזרה כבר בתור או פועל, כך שהשלב יבוצע בהצלחה מבלי להתחיל שלב נוסף.
  • הפונקציה Idempotency-Key יוצר תור של בקשה שניתנה שוב ללא כל פעולה פעמיים.
כאשר התרגום האוטומטי מופעל, כל סנכרון מתרגם את התוכן ששינה ומחייב אותו. הפעל את זרימת העבודה לאחר עריכות אמיתיות, לא בלוח זמנים קצר. ראה הפעלת סנכרון של Notion עם ממשק ה-API Notiondesk .

גבה כל מאמר כהורדת מחיר

היקף: read

שמור כל מאמר, בכל שפה שמרכז העזרה שלך מציע, כקובץ markdown:

הגיבוי כולל טיוטות ומאמרים מאוחסנים. הקריאות מוגבלות ל-120 בקשות לדקה, כך שמרכז עזרה עם 500 מאמרים לוקח כחמש דקות לכל שפה; העוזר ממתין אוטומטית כשהוא מגיע למגבלה.

שלח משוב שלילי לסלאק כל יום

היקף: read בלבד

פרסמו את 24 השעות האחרונות של משוב שלילי לערוץ Slack דרך webhook נכנס . הגדר SLACK_WEBHOOK_URL, ולאחר מכן הפעילו את הסקריפט פעם ביום.

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

import { mkdir, writeFile } from "node:fs/promises";
import { api, listAll, SITE_ID } from "./notiondesk.mjs";

const site = await api(`/sites/${SITE_ID}`);

for (const locale of site.supported_locales) {
  await mkdir(`backup/${locale}`, { recursive: true });
  const articles = await listAll(`/sites/${SITE_ID}/articles?locale=${locale}`);

  for (const article of articles) {
    const full = await api(`/sites/${SITE_ID}/articles/${encodeURIComponent(article.id)}?locale=${locale}`);
    const frontMatter = `---\ntitle: ${JSON.stringify(full.title ?? "")}\nstatus: ${full.status}\nurl: ${full.url ?? ""}\n---\n\n`;
    await writeFile(`backup/${locale}/${encodeURIComponent(article.id)}.md`, frontMatter + full.text);
    if (full.truncated) {
      console.warn(`${locale}/${article.id} is longer than 200,000 bytes and was truncated`);
    }
  }
  console.log(`${locale}: ${articles.length} articles saved`);
}
import { api, SITE_ID } from "./notiondesk.mjs";

const since = Date.now() - 24 * 60 * 60 * 1000;
const escapeSlack = (text) => (text ?? "").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");

async function feedbackSince(timestamp) {
  const entries = [];
  let cursor = null;
  do {
    const query = new URLSearchParams({ page_size: "100" });
    if (cursor) {
      query.set("cursor", cursor);
    }
    const page = await api(`/sites/${SITE_ID}/feedback?${query}`);
    const recent = page.data.filter((entry) => Date.parse(entry.submitted_at) >= timestamp);
    entries.push(...recent);
    cursor = page.has_more && recent.length === page.data.length ? page.next_cursor : null;
  } while (cursor);
  return entries;
}

const negative = (await feedbackSince(since)).filter(
  (entry) => entry.reaction_group === "negative" || entry.reaction_group === "not_helpful",
);

if (negative.length > 0) {
  const lines = negative.map(
    (entry) => `• *${escapeSlack(entry.article_title)}* (${entry.article_locale}): ${escapeSlack(entry.message) || "_no message_"}`,
  );
  await fetch(process.env.SLACK_WEBHOOK_URL, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ text: `${negative.length} negative feedback in the last 24 hours\n${lines.join("\n")}` }),
  });
}
המשוב נכתב על ידי הקוראים שלך. הפעל סקריפט זה עם מפתח שמכיל רק , צור תצורת escape מהטקסט לפני פרסומו, ולעולם אל תעביר אותו ל-LLM המחזיק מפתח המסוגל לכתוב. ראה ייצוא משוב קוראים עם ממשק ה-API Notiondesk .read

דווח על חיפושים ללא תוצאות בכל שבוע

היקף: read

רשום מה חיפשו הקוראים בשבוע שעבר מבלי למצוא מאמר. כל שאילתה היא מועמדת למאמר חדש או כותרת טובה יותר.

כל רשימת שאילתות מכילה עד 50 שורות. דוחות אנליטיקה חולקים גם תקציב של 30 בקשות לדקה לכל מרכז עזרה. ראה קבל ניתוחי מרכז עזרה באמצעות Notiondesk API .

מצא מאמרים שהסנכרון האחרון שלהם נכשל

היקף: read, ועוד sync כדי לנסות שוב

תקן תחילה כל מאמר ב-Notion, ולאחר מכן סנכרן אותו שוב עם POST /sites/{site_id}/articles/{article_id}/sync.

החל מותג אחד על כל מרכז עזרה

היקף: read ו-admin

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

כל עדכון מיתוג מרענן את כל מרכז העזרה של היעד, כך שהסקריפט שולח בקשה אחת לכל מרכז עזרה. צבע המאוחסן בצורה מקוצרת כגון #fff נדחה: תקן אותו תחילה בלוח המחוונים של מרכז העזרה המקורי. ראה התאמה אישית של מיתוג וערכות נושא של מרכז העזרה באמצעות ממשק ה-API Notiondesk .

ייבוא ​​הפניות לאחר הגירה

היקף: read ו-write

עוברים מכלי אחר במרכז העזרה? סקריפט ייבוא ​​ההפניות קורא קובץ CSV של נתיבים ישנים ויוצר הפניה אחת לכל שורה. ראה ניהול הפניות של דפים באמצעות ממשק ה-API Notiondesk .

import { api, SITE_ID } from "./notiondesk.mjs";

const end = new Date();
end.setUTCHours(0, 0, 0, 0);
const start = new Date(end.getTime() - 7 * 24 * 60 * 60 * 1000);
const toApiDate = (date) => `${date.toISOString().slice(0, 19)}Z`;

const query = new URLSearchParams({
  start_date: toApiDate(start),
  end_date: toApiDate(end),
  date_scale: "day",
});
const report = await api(`/sites/${SITE_ID}/analytics/search?${query}`);

console.log(`Searches: ${report.searches.total} (${report.searches.percentage_difference}% vs previous week)`);
console.log(`Without results: ${report.searches_without_results.total}`);
console.log(`Click-through rate: ${report.click_through_rate.current.toFixed(1)}%`);

for (const { query: text, searches } of report.searches_without_results.queries) {
  console.log(`${searches}\t${text}`);
}
import { api, listAll, SITE_ID } from "./notiondesk.mjs";

const articles = await listAll(`/sites/${SITE_ID}/articles`);
const failed = articles.filter((article) => article.sync_failed || article.sync_timeout);

for (const article of failed) {
  const reason = article.sync_timeout ? "timed out" : article.sync_error_code ?? "failed";
  console.log(`${article.title}: ${reason} ${article.notion_article_page_url ?? ""}`);
}
import { createHash } from "node:crypto";
import { api, listAll } from "./notiondesk.mjs";

const sourceId = process.env.SOURCE_SITE_ID;
const { colors, primary_font, secondary_font } = await api(`/sites/${sourceId}/settings/customize`);
const body = JSON.stringify({ colors, primary_font, secondary_font });
const bodyHash = createHash("sha256").update(body).digest("hex");
const sites = await listAll("/sites");

for (const site of sites.filter((candidate) => candidate.id !== sourceId)) {
  await api(`/sites/${site.id}/settings/customize`, {
    method: "PATCH",
    headers: { "Content-Type": "application/json", "Idempotency-Key": `brand-${site.id}-${bodyHash}` },
    body,
  });
  console.log(`Updated ${site.full_domain}`);
}

שאלות נפוצות

באיזו שפה אני יכול להשתמש עם ממשק ה-API של Notiondesk?

כל שפה שיכולה לשלוח בקשות HTTPS. ה-API הוא REST רגיל עם JSON, כך ש-curl, JavaScript, Python, PHP, Go או Ruby כולם עובדים.

איפה אני אמור להריץ את הסקריפטים האלה?

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

האם ניתן להשתמש בסקריפטים אלה עם OAuth במקום מפתח API?

כן. החלף את מפתח ה-API באסימון גישה של OAuth בכותרת Authorization, ורענן אותו לפני שפג תוקפו. ראה חבר את האפליקציה שלך ל-Notiondesk באמצעות OAuth .

מה הלאה

מאמרים קשורים

האם הדף הזה היה מועיל?

Still need help? Ask us