Zum Inhalt springen

Anleitung

Verbinden Sie jede beliebige Website per Webhook

Sie nutzen kein WordPress? Kein Problem. BlogTend sendet jeden fertigen Artikel per POST als signiertes JSON an einen Endpunkt unter Ihrer Kontrolle — mit jedem Technologiepaket, jedem CMS, mit etwa zwanzig Zeilen Code auf Ihrer Seite.

Was der Webhook-Konnektor ist

Sobald ein Artikel fertig generiert ist — oder sein geplanter Veröffentlichungszeitpunkt erreicht ist — sendet BlogTend ihn als eine JSON-POST-Anfrage an Ihren Endpunkt: Titel, vollständiges HTML, Auszug, SEO-Metadaten, Kategorie- und Schlagwortnamen, Sprache, Quellen, und eine öffentliche URL für das Beitragsbild. Ihr Endpunkt speichert ihn so, wie Ihre Website Inhalte speichert, und alles andere in BlogTend funktioniert genauso wie bei WordPress-Websites: Automatisierungen, Zeitplanung, Entwürfe, die Übersicht, Google-Indexierung.

Jede Anfrage wird mit einem Geheimnis signiert, das nur Sie und BlogTend kennen, sodass Ihr Endpunkt nachweisen kann, dass der Artikel wirklich von uns stammt und nicht manipuliert wurde.

Was Ihr Endpunkt leisten muss

  • Nehmen Sie eine HTTPS-POST-Anfrage mit JSON-Inhalt unter einer öffentlichen URL entgegen.
  • Antworten Sie innerhalb von 15 Sekunden mit einem 2xx-Statuscode. Führen Sie zeitaufwendige Vorgänge (Bilder herunterladen, Cache neu aufbauen) erst nach der Antwort aus, nicht davor.
  • Beantworten Sie jeden Ping mit einem 2xx-Statuscode. Ein Ping enthält keinen Artikel und darf keine Schreibvorgänge auslösen, daher können Sie ihn vor (oder ohne) seiner Verifizierung beantworten: So kann Testen & verbinden erfolgreich abgeschlossen werden, während Ihr geheimer Schlüssel noch bereitgestellt wird.
  • Prüfen Sie X-BlogTend-Signature bei jedem Artikelereignis (Code unten), und antworten Sie mit 401, wenn die Signatur nicht übereinstimmt. Wir erzwingen diese Prüfung nicht, aber ohne sie könnte jeder, der die URL findet, gefälschte Artikel an Ihre Website senden.
  • Verwenden Sie article.id als Idempotenzschlüssel: Wenn bereits ein Beitrag mit dieser ID existiert, aktualisieren Sie ihn, statt ein Duplikat zu erstellen.
  • Wenn Sie eine Anfrage ablehnen, geben Sie den Grund im Antworttext an (zum Beispiel {"error": "ungültige Signatur"}). Wir zeigen die ersten 300 Zeichen in Ihrem Zustellungsprotokoll an.

Verbindung herstellen

  1. Stellen Sie Ihren Empfangsendpunkt bereit (das Beispiel unten ist eine vollständige Implementierung).
  2. Gehen Sie in BlogTend zu Websites → Website verbinden → Webhook, geben Sie einen Namen und die Endpunkt-URL ein, und klicken Sie auf Weiter.
  3. Wir zeigen den Signaturschlüssel whsec_… an. Kopieren Sie ihn jetzt in die Umgebungsvariablen Ihres Servers und stellen Sie die Anwendung bereit: Der Schlüssel wird nur auf dieser Seite angezeigt.
  4. Klicken Sie auf Testen & verbinden. Wir senden einen mit diesem Geheimschlüssel signierten Ping; bei einem 2xx-Status wird die Verbindung gespeichert. Wenn Ihr Endpunkt ihn ablehnt, zeigen wir dessen Status und Fehlermeldung an, damit Sie das Problem beheben und erneut auf Testen & verbinden klicken können.

Wenn Sie dieselbe URL erneut verbinden (um die Website umzubenennen, oder nach einem Fehler), bleibt der geheime Schlüssel unverändert: Der Dialog zeigt den aktuellen Schlüssel an und die Testanfrage wird damit signiert. Um einen neuen geheimen Schlüssel zu erhalten, erneuern Sie ihn.

Von uns gesendete Header

Jede Anfrage, ob Ping oder Artikel, enthält diese Header:

HeaderWertNotizen
X-BlogTend-Signaturet=<unix seconds>,v1=<hex>[,v1=<hex>]HMAC-SHA256-Signatur. Ein v1 pro aktivem geheimem Schlüssel: zwei nur während der 24-stündigen Übergangsfrist bei einer Rotation, der neueste zuerst.
X-BlogTend-Eventping | article.published | article.updatedIdentisch mit dem Feld event im Nachrichtenkörper.
X-BlogTend-Deliverywhd_…Identisch mit delivery_id im Nachrichtenkörper. Bei jedem Versuch neu, auch bei Wiederholungen.
X-BlogTend-Test1Nur bei Pings (Testen & verbinden, Erneut verifizieren, Kategorien aktualisieren). Ein Ping enthält keinen Artikel und darf nichts schreiben.
Content-Typeapplication/jsonDer Nachrichtenkörper enthält UTF-8-kodiertes JSON.
User-AgentBlogTend-Webhook/1Hieß vor der Umbenennung YoDon-Webhook/1.
X-Yodon-Signature, X-Yodon-Event, X-Yodon-DeliverydeprecatedWird für Empfänger gesendet, die vor der Umbenennung entwickelt wurden, mit denselben Werten, außer dass X-Yodon-Signature immer genau eine v1 enthält, die mit dem neuesten Geheimschlüssel erstellt wurde. Neue Empfänger sollten die X-BlogTend-* Header auslesen.

Die X-Yodon-* Header sind veraltet. Sie funktionieren weiterhin für Empfänger, die vor der Umbenennung entwickelt wurden, aber nur X-BlogTend-Signature enthält während eines Schlüsselwechsels beide Signaturen, wechseln Sie daher bei der nächsten Anpassung Ihres Empfängers zu den neuen Namen.

Die Nutzdaten, Feld für Feld

Es gehen drei Ereignistypen ein, die sich anhand des Feldes event und des Headers X-BlogTend-Event unterscheiden: ping (Verbindungstest, kein Artikel), article.published (erste Übermittlung eines Artikels) und article.updated (derselbe Artikel erneut: nach einem von Ihnen ausgelösten erneuten Versuch, der Veröffentlichung eines Entwurfs oder der Aktualisierung eines bereits veröffentlichten Beitrags, wobei url den zu ersetzenden veröffentlichten Beitrag angibt und id die ID ist, die Sie dafür gespeichert haben). Die vollständige Struktur:

{
  "event": "article.published",
  "delivery_id": "whd_5f0c9c1e-…",
  "site_id": "d2a41c3e-…",
  "sent_at": "2026-08-28T15:04:05.000Z",
  "article": {
    "id": "a81f6a02-…",
    "title": "How to Choose a Standing Desk",
    "slug": "how-to-choose-a-standing-desk",
    "status": "publish",
    "html": "<h2>…</h2><p>…</p>",
    "excerpt": "A practical buyer's guide…",
    "seo": {
      "title": "Standing Desk Buyer's Guide (2026)",
      "description": "Everything to check before…",
      "keyword": "standing desk"
    },
    "category": "Office Setup",
    "categories": ["Office Setup", "Buying Guides"],
    "tags": ["desks", "ergonomics"],
    "language": "en",
    "featured_image": {
      "url": "https://www.blogtend.com/api/images/…?sig=…",
      "mime": "image/webp"
    },
    "sources": [{ "title": "OSHA guidance", "url": "https://…" }],
    "published_at": "2026-08-28T15:04:05.000Z",
    "updated_at": "2026-08-28T15:04:05.000Z",
    "url": "https://example.com/blog/how-to-choose-a-standing-desk"
  }
}
  • article.status ist der von uns angeforderte Status: "publish" oder "draft". Geplante Artikel werden zum geplanten Zeitpunkt mit "publish" übermittelt.
  • article.html enthält den vollständigen Artikelinhalt. Die darin enthaltenen Bildverweise zeigen bereits auf öffentlich zugängliche URLs.
  • category und categories sind Namen, keine IDs — ordnen Sie sie Ihrer eigenen Taxonomie zu, oder ignorieren Sie sie.
  • featured_image ist null, wenn der Artikel kein Bild enthält. Die URL ist signiert und dauerhaft gültig — rufen Sie sie jederzeit ab.
  • delivery_id kennzeichnet diesen einzelnen Versuch und ändert sich bei jedem erneuten Versuch; article.id kennzeichnet den Artikel und bleibt immer gleich. Erkennen Sie Duplikate anhand von article.id.
  • Der Nachrichteninhalt eines Pings enthält nur event, delivery_id, site_id und sent_at; keinen Artikel.

Signaturprüfung

Jede Anfrage enthält X-BlogTend-Signature: t=<unix seconds>,v1=<hex>. Jeder v1-Wert ist ein HMAC-SHA256 der Zeichenfolge "<t>.<raw body>" mit einem whsec_-Geheimnis als Schlüssel. Prüfen Sie die Signatur anhand des unverarbeiteten Anfrageinhalts, bevor Sie JSON parsen, lehnen Sie Zeitstempel mit mehr als 5 Minuten Abweichung ab, vergleichen Sie mit einer zeitkonstanten Funktion, und akzeptieren Sie die Anfrage, wenn einer der v1-Werte zu Ihrem Geheimnis passt: während einer Schlüsselrotation gibt es zwei.

Node.js

import crypto from "crypto";

// header: the X-BlogTend-Signature value, e.g. "t=1767225600,v1=ab12…,v1=cd34…".
// During a secret rotation it holds one v1 per live secret: accept if ANY matches.
export function verifyBlogTendSignature(secret, header, rawBody) {
  const parts = (header || "").split(",").map((p) => p.trim());
  const t = parts.find((p) => p.startsWith("t="))?.slice(2);
  // Reject anything older than 5 minutes: replay protection.
  if (!t || Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
  const expected = Buffer.from(
    crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex")
  );
  return parts
    .filter((p) => p.startsWith("v1="))
    .map((p) => Buffer.from(p.slice(3)))
    .some((sig) => sig.length === expected.length && crypto.timingSafeEqual(sig, expected));
}

PHP

function verify_blogtend_signature(string $secret, string $header, string $rawBody): bool {
    $t = null;
    $sigs = [];
    foreach (explode(',', $header) as $part) {
        [$k, $v] = array_pad(explode('=', trim($part), 2), 2, '');
        if ($k === 't') $t = $v;
        if ($k === 'v1') $sigs[] = $v;                      // one per live secret
    }
    if (!ctype_digit((string) $t) || abs(time() - (int) $t) > 300) return false; // replay window
    $expected = hash_hmac('sha256', $t . '.' . $rawBody, $secret);
    foreach ($sigs as $sig) {
        if (hash_equals($expected, $sig)) return true;      // timing-safe
    }
    return false;
}

Python

import hashlib, hmac, time

def verify_blogtend_signature(secret: str, header: str, raw_body: bytes) -> bool:
    parts = [p.strip().split("=", 1) for p in (header or "").split(",") if "=" in p]
    t = next((v for k, v in parts if k == "t"), "")
    if not t.isdigit() or abs(time.time() - int(t)) > 300:   # replay window
        return False
    expected = hmac.new(
        secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256
    ).hexdigest()
    # One v1 per live secret during a rotation: accept if any matches.
    return any(hmac.compare_digest(expected, v) for k, v in parts if k == "v1")

Ein älterer Empfänger, der X-Yodon-Signature mit einem Muster für genau einen v1-Wert ausliest, funktioniert weiterhin: Dieser Header enthält nach wie vor genau einen v1-Wert, der mit dem neuesten geheimen Schlüssel erzeugt wird.

Geheimschlüssel erneuern

Haben Sie den geheimen Schlüssel verloren oder wechseln Sie ihn regelmäßig? Öffnen Sie auf der Seite Websites die Karte der Webhook-Website und klicken Sie auf Geheimen Schlüssel wechseln. Der neue geheime Schlüssel wird nur einmal angezeigt.

  • In den nächsten 24 Stunden enthält jede Anfrage zwei Signaturen in X-BlogTend-Signature: eine mit dem neuen geheimen Schlüssel erstellte und eine mit dem alten. Der Empfänger kann die Anfrage mit jedem der beiden Schlüssel verifizieren, sodass nichts fehlschlägt, während Sie Ihren Server aktualisieren.
  • Nach 24 Stunden wird nur noch mit dem neuen geheimen Schlüssel signiert. Die Karte zeigt an, wann der alte nicht mehr verwendet wird.
  • Falls der alte geheime Schlüssel offengelegt wurde, aktivieren Sie beim Wechsel "sofort deaktivieren": Es gibt keine Übergangsfrist, und Zustellungen schlagen mit 401 fehl, bis Ihr Server den neuen geheimen Schlüssel hat.
  • Empfänger, die noch den veralteten X-Yodon-Signature auslesen, sehen nur die Signatur des neuen geheimen Schlüssels, sodass die Umstellung für sie sofort erfolgt.

Antwortinhalt

Jeder 2xx-Status gilt als erfolgreiche Zustellung; der Antwortinhalt ist optional und darf leer sein. Antworten Sie mit JSON und BlogTend wird intelligenter:

{ "ok": true, "id": "123", "url": "https://example.com/blog/my-post" }
  • url — wird als Link zum veröffentlichten Artikel gespeichert: Die Schaltfläche „Ansehen“ im Dashboard öffnet ihn, und er wird zur Indexierung bei Google eingereicht.
  • id — die Kennung Ihres Beitrags, die gespeichert wird, damit künftige article.updated-Ereignisse auch auf Ihrer Seite zugeordnet werden können.
  • held — eine kurze Begründung, wenn Sie den Artikel angenommen, aber nicht auf Ihrer Website veröffentlicht haben (eine redaktionelle Warteschlange, eine interne Regel). BlogTend zeigt ihn dann mit dieser Begründung als Entwurf statt als veröffentlichten Beitrag an und versendet keine E-Mail mit "veröffentlicht". Eine Antwort mit status: "draft" bewirkt dasselbe ohne Begründung.

Auch bei einem Ping reicht jeder 2xx-Statuscode aus. Das einzige Feld, das wir aus einer Ping-Antwort auslesen, ist categories: Antworten Sie mit { ok: true, categories: ["Guides", "News"] } (einem Array mit bis zu 100 Namen), damit diese Namen in den Erstellungsformularen von BlogTend als auswählbare Kategorien erscheinen. Die Liste wird bei jeder erneuten Verifizierung und über die Aktualisierungsschaltfläche der Kategorieauswahl aktualisiert. Lassen Sie das Feld weg, schlägt die KI stattdessen einfach Kategorienamen vor.

Fehler, Wiederholungsversuche und Duplikate

So wertet BlogTend jede Antwort auf eine Artikelübermittlung aus:

Ihre AntwortWas es für uns bedeutetErneut gesendet?
2xxZugestellt. Der Antwortinhalt ist optional; ein JSON-Antwortinhalt wird wie unter Was Sie zurückgeben sollten beschrieben ausgelesen.Erledigt.
3xxFehlgeschlagen. Weiterleitungen werden nicht verfolgt: Verbinden Sie stattdessen die endgültige URL.Nicht sofort erneut gesendet.
401 / 403Fehlgeschlagen: angezeigt als "Signatur abgelehnt". Der geheime Schlüssel auf Ihrem Server stimmt nicht überein. Fügen Sie ihn erneut ein oder ersetzen Sie ihn durch einen neuen.Nicht sofort erneut gesendet.
503Fehlgeschlagen: angezeigt als "noch nicht konfiguriert", die übliche Antwort eines Empfängers, für den kein geheimer Schlüssel festgelegt ist.Einmal erneut gesendet, ohne Verzögerung.
Sonstige 4xxFehlgeschlagen: Sie haben die Anfrage verstanden und abgelehnt.Nicht sofort erneut gesendet.
Sonstige 5xxFehlgeschlagen: Ihr Endpunkt ist abgestürzt oder nicht erreichbar.Einmal erneut gesendet, ohne Verzögerung.
Keine Antwort innerhalb von 15 s, oder ein NetzwerkfehlerFehlgeschlagen: angezeigt als "Ihr Endpunkt konnte nicht erreicht werden".Einmal erneut gesendet, ohne Verzögerung.
  • Artikel, die BlogTend selbstständig veröffentlicht (Automatisierungen und geplante Beiträge): wenn eine Übermittlung weiterhin fehlschlägt, wird der gesamte Artikel in den nächsten zwei Durchläufen im Abstand von etwa einer Minute erneut übermittelt, unabhängig von der Antwort. Nach dem dritten fehlgeschlagenen Versuch stoppt BlogTend, behält den fertigen Artikel und teilt Ihnen den Grund per E-Mail mit. Veröffentlichen Sie ihn erneut, sobald Ihr Endpunkt wieder funktioniert.
  • Artikel, die Sie manuell veröffentlichen: kein automatischer Wiederholungsversuch. Der Grund wird sofort beim Artikel angezeigt; klicken Sie erneut auf Veröffentlichen, oder auf Erneut versuchen unter Letzte Zustellungen.
  • Kein Artikel geht verloren: Schlägt die Veröffentlichung fehl, bleibt er mit der Fehlerursache in BlogTend, bereit für einen erneuten Versuch.
  • Hier finden Sie die Details: Auf der Seite Websites enthält die Karte einer Webhook-Website den Bereich Letzte Zustellungen. Jeder Eintrag zeigt den Statuscode, seine übliche Bedeutung und die ersten 300 Zeichen Ihrer Fehlermeldung; fehlgeschlagene Zustellungen haben eine Schaltfläche Erneut versuchen. Das erste Kilobyte jeder Antwort wird gespeichert.
  • Durch Wiederholungsversuche kann Ihr Endpunkt denselben Artikel zweimal empfangen, jeweils mit einer neuen delivery_id. Deshalb ist es wichtig, anhand von article.id vorhandene Artikel zu aktualisieren und neue einzufügen.

Ein vollständiges Beispiel für einen Empfänger

Eine Route im Next.js App Router, die prüft, Duplikate entfernt und speichert. Ersetzen Sie savePost durch Ihre eigene Speicherlogik und sie ist produktionsreif:

// app/api/articles/webhook/route.ts — a complete Next.js receiver
import { NextResponse } from "next/server";
import { verifyBlogTendSignature } from "./verify"; // the Node.js function above

const SECRET = process.env.BLOGTEND_WEBHOOK_SECRET; // the whsec_… shown when you connected

export async function POST(req: Request) {
  const body = await req.text(); // raw body — verify BEFORE parsing
  let payload;
  try {
    payload = JSON.parse(body);
  } catch {
    return NextResponse.json({ error: "invalid JSON" }, { status: 400 });
  }

  // A ping carries no article and writes nothing, so it is answered without
  // verifying: Test & connect then passes even before SECRET is deployed.
  // Return nothing private here.
  if (payload.event === "ping") {
    // Optional: advertise your categories so BlogTend's forms can offer them.
    return NextResponse.json({ ok: true, categories: await listMyCategories() });
  }

  // Every content event must be verified. Clear messages here show up in
  // BlogTend's delivery log, so "wrong secret" never looks like "down".
  if (!SECRET) {
    return NextResponse.json({ error: "receiver not configured: BLOGTEND_WEBHOOK_SECRET is not set" }, { status: 503 });
  }
  const header =
    req.headers.get("x-blogtend-signature") ?? req.headers.get("x-yodon-signature") ?? "";
  if (!verifyBlogTendSignature(SECRET, header, body)) {
    return NextResponse.json({ error: "invalid signature: check BLOGTEND_WEBHOOK_SECRET" }, { status: 401 });
  }

  const a = payload.article;
  // Upsert by a.id — retries and updates must not create duplicates.
  const post = await savePost({
    externalId: a.id,
    slug: a.slug,
    title: a.title,
    html: a.html,
    excerpt: a.excerpt,
    metaTitle: a.seo.title,
    metaDescription: a.seo.description,
    tags: a.tags,
    category: a.category,
    imageUrl: a.featured_image?.url ?? null,
    published: a.status === "publish",
  });

  // Answer with the live URL so the BlogTend dashboard links to the post.
  return NextResponse.json({ ok: true, id: post.id, url: post.url });
}

Dieselbe Logik lässt sich in wenigen Minuten auf jedes Framework übertragen — die FAQ unten beantworten die häufigsten Fragen zu den Plattformen.

Fragen

Mit welchen Plattformen funktioniert das?
Jede technische Plattform, die einen HTTPS-POST empfangen kann: Next.js, Laravel, Django, Rails, Express, ein Cloudflare Worker, ein No-Code-Tool wie Make oder n8n, ein eigenes CMS — wenn sie eine URL hat, kann sie Artikel empfangen.
Ich habe den Signaturschlüssel verloren. Wo finde ich ihn wieder?
Nirgendwo: Wir speichern ihn verschlüsselt und zeigen ihn nur beim Verbinden an. Wählen Sie Geheimschlüssel erneuern auf der Website-Karte unter Websites. Sie erhalten einen neuen Geheimschlüssel, und der alte wird parallel dazu noch 24 Stunden lang zum Signieren verwendet, damit die Zustellung weiterhin funktioniert, während Sie Ihren Server aktualisieren.
Funktioniert die zeitgesteuerte Veröffentlichung von Artikeln?
Ja. Die Zeitplanung übernimmt BlogTend: zum geplanten Zeitpunkt senden wir den Artikel mit dem Status "publish". Ihr Endpunkt muss keine Zeitplanung implementieren.
Was ist mit Entwürfen?
Ein als Entwurf gesendeter Artikel kommt mit dem Status "draft" an. Was das auf Ihrer Website bedeutet, entscheiden Sie — die meisten Empfänger speichern den Beitrag unveröffentlicht. Wenn Sie später in BlogTend auf Veröffentlichen klicken, wird derselbe Artikel erneut als article.updated-Ereignis mit dem Status "publish" übermittelt.
Wie werden Bilder übermittelt?
Das Beitragsbild ist über eine signierte öffentliche URL auf unseren Servern verfügbar (featured_image.url), und der HTML-Code des Artikels verweist auf dieselbe URL. Laden Sie es herunter und hosten Sie es selbst, oder liefern Sie es direkt von unseren Servern aus — beides funktioniert.
Werden die Nutzdaten bei Fehlern erneut gesendet? Erhalte ich Duplikate?
Ja. Eine fehlgeschlagene Zustellung wird erneut versucht, und jeder Versuch erhält eine neue delivery_id, sodass Ihr Endpunkt denselben Artikel mehrfach empfangen kann. Verwenden Sie article.id als Idempotenzschlüssel: Aktualisieren Sie den bestehenden Beitrag, statt einen zweiten anzulegen, und Duplikate sind ausgeschlossen.
Werden SEO-Metadaten übertragen?
Ja — seo.title, seo.description und seo.keyword werden mit jedem Artikel übermittelt, ebenso wie der Auszug, Schlagwörter, Kategorienamen und die Sprache. Nutzen Sie, was Ihre Plattform unterstützt, und ignorieren Sie den Rest.

Stattdessen auf WordPress veröffentlichen? Lesen Sie die WordPress-Anleitung

Ihre Infrastruktur, unsere Artikel

Verbinden Sie einmal einen Endpunkt und jeder Artikel — manuell, per Massenerstellung oder automatisiert — gelangt direkt auf Ihre Website.