Custom Backend verbinden

blog-maker kann Artikel an jedes Backend veröffentlichen, das einen JSON-HTTP-Endpoint anbietet, nicht nur an WordPress. Diese Seite ist die technische Referenz, um dein eigenes PHP-, Node- oder anderes Backend anzubinden.

Wann sinnvoll

Nutze einen Custom-REST-Endpoint, wenn deine Seite auf einem proprietären CMS, einem eigenen PHP-Backend oder etwas anderem als WordPress/WooCommerce läuft. Einmal im Dashboard deiner Brand eingerichtet, veröffentlicht danach jeder Artikel direkt in deinen eigenen Speicher.

Konfigurations-Schema

Die Verbindung wird über ein kleines JSON-Config mit diesen Feldern beschrieben:

FeldTypBeschreibung
endpointstring, requiredDie URL, an die wir den veröffentlichten Beitrag senden.
method"POST" | "PUT" | "PATCH", optionalHTTP-Methode für die Anfrage. Standard: POST.
authobject, requiredWie wir uns authentifizieren: Bearer-Token, Basic Auth, ein eigener Header oder keine.
payloadTemplateJSON, requiredDer JSON-Body, den wir senden, mit {{tokens}} aus dem Artikel gefüllt.
successPathstring, optionalGepunkteter Pfad in der Antwort, der truthy sein muss, damit die Veröffentlichung als erfolgreich zählt.
postIdPathstring, optional (default "id")Gepunkteter Pfad zur neuen Post-ID in der Antwort.
postUrlPathstring, optionalGepunkteter Pfad zur veröffentlichten URL in der Antwort.
pingEndpointstring, optionalEine separate URL, die nur für den Verbindungstest genutzt wird.
timeoutMsnumber, optional (default 30000)Anfrage-Timeout in Millisekunden.

Authentifizierung

Vier Wege, sich zu authentifizieren, pro Verbindung wählbar:

TypFelderGesendet alsHinweis
bearertokenAuthorization: Bearer <token>Empfohlen.
basicusername, passwordAuthorization: Basic base64(user:pass)Nur für Altsysteme.
headerheaderName, headerValue<headerName>: <headerValue>Ein beliebiger Header, den dein Backend erwartet.
none(none)no auth headerFür Endpoints ohne eigene Authentifizierung.

Verfügbare Tokens

Nutze diese in deinem Payload-Template; jeder String im Template wird durchsucht und Tokens werden mit den Artikeldaten gefüllt.

TokenBeschreibung
{{id}}Numerische Artikel-ID.
{{title}} / {{seoTitle}}SEO-Titel.
{{seoDescription}}Meta-Description.
{{html}} / {{htmlContent}}Vollständiger HTML-Body.
{{slug}} / {{urlSlug}}URL-Slug.
{{primaryKeyword}}Fokus-Keyword.
{{secondaryKeywords}}Weitere Keywords, kommagetrennt.
{{postId}}Post-ID, nur bei der Aktualisierung eines bestehenden Beitrags vorhanden.

Beispiel-Payload-Template

{
  "title": "{{title}}",
  "slug": "{{slug}}",
  "html": "{{html}}",
  "metaDescription": "{{seoDescription}}",
  "primaryKeyword": "{{primaryKeyword}}"
}

Beispiel-Request und erwartete Antwort

POST https://example.com/api/receive-post
Content-Type: application/json
Accept: application/json
Authorization: Bearer sk_live_xxxxx

{
  "title": "How to set up blog automation",
  "slug": "how-to-set-up-blog-automation",
  "html": "<p>...</p>",
  "metaDescription": "Learn step by step how content automation works.",
  "primaryKeyword": "blog automation"
}
{
  "ok": true,
  "id": "post-123",
  "url": "https://example.com/blog/how-to-set-up-blog-automation"
}
  • successPath (z.B. "ok"): muss truthy sein, sonst gilt die Veröffentlichung als fehlgeschlagen.
  • postIdPath (Standard "id"): Pfad zur Post-ID, auch verschachtelt möglich, z.B. "data.id".
  • postUrlPath (optional): Pfad zur veröffentlichten URL.

Bei einem Fehler (kein 2xx, oder successPath falsy) erscheinen die ersten Zeichen deiner Antwort als Fehlermeldung im Dashboard, damit du von dort aus debuggen kannst.

Receiver-Beispiel

Ein fertiger Mini-Server, den du deinem Entwickler geben kannst. Er prüft den Bearer-Token, speichert den Artikel und antwortet im erwarteten Format.

PHP

<?php
// Minimal blog-maker custom_rest receiver.
// Expects: Authorization: Bearer <token>, JSON body per your payload template.

$expectedToken = getenv('BLOG_MAKER_TOKEN') ?: 'change-me';
$headers = getallheaders();
$auth = $headers['Authorization'] ?? '';

if ($auth !== "Bearer $expectedToken") {
    http_response_code(401);
    echo json_encode(['ok' => false, 'error' => 'Unauthorized']);
    exit;
}

$body = json_decode(file_get_contents('php://input'), true);
if (!$body || empty($body['title']) || empty($body['html'])) {
    http_response_code(400);
    echo json_encode(['ok' => false, 'error' => 'Missing title or html']);
    exit;
}

// postId is present on updates; create a new id otherwise.
$postId = $body['postId'] ?? bin2hex(random_bytes(6));
$posts = json_decode(@file_get_contents('posts.json') ?: '{}', true) ?: [];

$posts[$postId] = [
    'title' => $body['title'],
    'slug' => $body['slug'] ?? '',
    'html' => $body['html'],
    'metaDescription' => $body['metaDescription'] ?? '',
];

file_put_contents('posts.json', json_encode($posts));

echo json_encode([
    'ok' => true,
    'id' => $postId,
    'url' => "https://example.com/blog/{$body['slug']}",
]);

Node.js

// Minimal blog-maker custom_rest receiver (plain Node, no framework).
// Run with: node receiver.js
import { createServer } from "node:http";
import { randomBytes } from "node:crypto";

const TOKEN = process.env.BLOG_MAKER_TOKEN || "change-me";
const posts = new Map();

const server = createServer((req, res) => {
  if (req.method !== "POST" && req.method !== "PUT") {
    res.writeHead(405).end();
    return;
  }
  if (req.headers.authorization !== `Bearer ${TOKEN}`) {
    res.writeHead(401, { "Content-Type": "application/json" });
    res.end(JSON.stringify({ ok: false, error: "Unauthorized" }));
    return;
  }

  let raw = "";
  req.on("data", (chunk) => (raw += chunk));
  req.on("end", () => {
    const body = JSON.parse(raw || "{}");
    if (!body.title || !body.html) {
      res.writeHead(400, { "Content-Type": "application/json" });
      res.end(JSON.stringify({ ok: false, error: "Missing title or html" }));
      return;
    }

    // postId is present on updates; create a new id otherwise.
    const postId = body.postId || randomBytes(6).toString("hex");
    posts.set(postId, body);

    res.writeHead(200, { "Content-Type": "application/json" });
    res.end(JSON.stringify({
      ok: true,
      id: postId,
      url: `https://example.com/blog/${body.slug}`,
    }));
  });
});

server.listen(3999, () => console.log("Receiver listening on :3999"));

Sicherheit

  • Zugangsdaten (Tokens, Passwörter, Header-Werte) werden mit AES-256-GCM verschlüsselt gespeichert.
  • Eine Verbindung ist an deine Brand gebunden; nur du oder Nutzer mit Schreibzugriff auf diese Brand können sie anlegen oder testen.
  • Wir blockieren Anfragen an private und interne Netzwerk-Adressen, auch wenn dein Endpoint dorthin weiterleitet.
  • Verbindungstests sind pro Nutzer rate-limitiert.
  • Custom-REST-Endpoints sind ab dem Basic-Plan verfügbar.