Kostenlos starten
API-Dokumentation · v1

API rewriter.io

Rufe über eine einfache, gut dokumentierte Read-only-API veröffentlichte Artikel aus deinem Projekt ab - direkt in deinen eigenen Blog. REST, JSON, API-Schlüssel, Filterung, Sortierung und Paginierung.

Einführung

Die Basis-URL der API lautet https://public-api.rewriter.io/v1. Alle Antworten werden im JSON-Format zurückgegeben (Schlüssel im snake_case-Stil), und der Artikeltext ist verfügbar als markdown und html. Jede Anfrage erfordert einen API-Schlüssel. Die API unterstützt ausschließlich den Lesezugriff auf veröffentlichte Inhalte.

Tipp: einen API-Schlüssel generierst du im Dashboard im Bereich Konto → API & Integrationen. Bewahre ihn serverseitig auf - binde ihn nicht in Front-End-Code ein.

Verwende in der Testumgebung die Adresse https://dev-hooks.rewriter.io/v1.

Für KI-Agenten und LLMs stellen wir einen maschinenlesbaren Index dieser Dokumentation bereit unter llms.txt.

Authentifizierung

Übergib den Schlüssel im Header Authorization als Bearer-Token. Der Schlüssel ist mit einem einzigen Projekt verknüpft.

terminal
# Prüfen, zu welchem Projekt der Schlüssel gehört
curl https://public-api.rewriter.io/v1/me \
  -H "Authorization: Bearer rw_live_3f8a…"

Limits und Versionierung

Die API ist im Pfad versioniert (/v1). Das Anfragelimit hängt vom Tarif ab und wird für jeden API-Schlüssel separat gezählt.

TarifLimit / Min.
Start60
Solo150
Pro300
Max1.000

Antworten für Tarife mit Limit enthalten die Header X-RateLimit-Limit, X-RateLimit-Remaining und X-RateLimit-Reset. Bei einem unbegrenzten Tarif werden keine X-RateLimit-*-Header gesendet.

  • GET-Anfragen sind aus dem Browser zugänglich (CORS).
  • Alle Zeitstempel im Format ISO 8601 (UTC).

Fehler

Fehler geben wir mit dem passenden HTTP-Code und einer einheitlichen Struktur zurück:

error
{
  "error": {
    "code": "not_found",
    "message": "Article not found."
  }
}
  • 400 - ungültige Abfrageparameter
  • 401 - fehlender oder ungültiger API-Schlüssel
  • 403 - dein Tarif umfasst keinen API-Zugriff
  • 404 - nicht gefunden (Artikel nicht veröffentlicht oder außerhalb des Projekts)
  • 429 - Anfragelimit überschritten
  • 500 - Serverfehler

Paginierung und Sortierung

Listen geben wir in einem Umschlag mit Datenfeldern und Seiten-Metadaten zurück:

GET /v1/articles
{
  "data": [
    "…"
  ],
  "page": 1,
  "per_page": 10,
  "total": 42
}

Die Paginierung steuerst du mit den Parametern page (ab 1) und limit (Standard 10, max. 100). Die Sortierung legst du mit dem Parameter sort fest - das Präfix „-” bedeutet absteigende Reihenfolge. Zulässige Werte: published_at, -published_at, title, -title, updated_at, -updated_at.

Projekt

GET/v1/me

Gibt Informationen über das mit dem Schlüssel verknüpfte Projekt sowie die verfügbaren Sprachen zurück. Nützlich zur Überprüfung des Schlüssels.

GET /v1/me
{
  "id": "k17a9c…",
  "name": "Kawiarnia Pod Lipą",
  "primary_language": "pl",
  "available_languages": [
    "pl",
    "en"
  ],
  "plan": "Pro",
  "rate_limit_per_minute": 300
}

Themen

GET/v1/topics

Gibt die Liste der Projektthemen zurück. Verwende das Feld id als Wert des Filters topic_id in der Artikelliste.

GET /v1/topics
{
  "data": [
    {
      "id": "j57b2…",
      "title": "Lokalne SEO"
    },
    {
      "id": "j58c1…",
      "title": "Porady baristów"
    }
  ]
}

Kategorien

GET/v1/categories

Gibt die Liste der Projektkategorien zurück. Verwende das Feld id als Wert des Filters category_id in der Artikelliste. Die Namen folgen dem Parameter language (Standard: Hauptsprache).

GET /v1/categories
{
  "data": [
    {
      "id": "k20a1…",
      "name": "Pielęgnacja ogrodu",
      "slug": "pielegnacja-ogrodu"
    },
    {
      "id": "k20a2…",
      "name": "Porady",
      "slug": "porady"
    }
  ]
}

Artikel auflisten

GET/v1/articles

Gibt eine paginierte Liste veröffentlichter Artikel zurück (Zusammenfassungsfelder, ohne Text).

Abfrageparameter

  • topic_id - string, optional. Nach Themen-Identifikator filtern.
  • category_id - string, optional. Nach Kategorie-Identifikator filtern.
  • language - string, optional. Sprachcode; standardmäßig die Hauptsprache des Projekts. Ein anderer Code gibt veröffentlichte Übersetzungen zurück.
  • q - string, optional. Suche nach Titel (ohne Unterscheidung von Groß- und Kleinschreibung).
  • published_after - ISO-8601-Datum, optional. Nur Artikel, die ab diesem Datum veröffentlicht wurden.
  • published_before - ISO-8601-Datum, optional. Nur Artikel, die bis zu diesem Datum veröffentlicht wurden.
  • sort - string, Standard -published_at. Siehe Abschnitt Paginierung und Sortierung.
  • page - Zahl, Standard 1.
  • limit - Zahl, Standard 10, max. 100.

Lass einen Parameter, den du nicht brauchst, einfach weg - ein leerer Wert (z. B. sort=) wird genauso behandelt wie ein fehlender Parameter.

GET /v1/articles?sort=-published_at&limit=10
{
  "data": [
    {
      "id": "m93f7…",
      "title": "10 sposobów na lokalne SEO",
      "slug": "10-sposobow-na-lokalne-seo",
      "language": "pl",
      "topic_id": "j57b2…",
      "category": {
        "id": "k20a1…",
        "name": "Pielęgnacja ogrodu",
        "slug": "pielegnacja-ogrodu"
      },
      "status": "published",
      "seo_score": 96,
      "readability_score": 72,
      "fact_check_status": "passed",
      "cover_image": "https://cdn.example.com/articles/m93f7/cover.png",
      "published_at": "2026-05-21T09:12:00.000Z",
      "updated_at": "2026-05-22T10:00:00.000Z"
    }
  ],
  "page": 1,
  "per_page": 10,
  "total": 42
}

Artikel abrufen

GET/v1/articles/:id

Gibt den vollständigen Text eines veröffentlichten Artikels samt SEO-Metadaten zurück. Der Text ist als Markdown und als HTML-Fragment verfügbar. Der Parameter :id akzeptiert die vollständige Artikel-ID; der rewriter.io-Blog akzeptiert zusätzlich eine slug-8-Zeichen-Referenz.

Abfrageparameter

  • language - string, optional. Sprachcode, um eine veröffentlichte Übersetzung statt der Version in der Hauptsprache abzurufen.
  • format - markdown oder html, optional. Standardmäßig geben wir beide Textfelder zurück.
GET /v1/articles/m93f7…
{
  "id": "m93f7…",
  "title": "10 sposobów na lokalne SEO",
  "slug": "10-sposobow-na-lokalne-seo",
  "topic_id": "j57b2…",
  "category": {
    "id": "k20a1…",
    "name": "Pielęgnacja ogrodu",
    "slug": "pielegnacja-ogrodu"
  },
  "language": "pl",
  "status": "published",
  "body_markdown": "## Wstęp\n\nLokalne SEO to…",
  "body_html": "<h2>Wstęp</h2>\n<p>Lokalne SEO to…</p>",
  "cover_image": "https://cdn.example.com/articles/m93f7/cover.png",
  "meta_title": "Lokalne SEO dla kawiarni",
  "meta_description": "Praktyczny przewodnik po lokalnym SEO.",
  "seo_score": 96,
  "readability_score": 72,
  "readability_label": "łatwy",
  "fact_check_status": "passed",
  "uniqueness_score": 98,
  "alternate_slugs": [
    {
      "language": "pl",
      "slug": "10-sposobow-na-lokalne-seo"
    },
    {
      "language": "en",
      "slug": "10-ways-to-improve-local-seo"
    }
  ],
  "json_ld": {
    "@context": "https://schema.org",
    "@type": "BlogPosting",
    "headline": "10 sposobów na lokalne SEO",
    "inLanguage": "pl",
    "wordCount": 1240,
    "…": "…"
  },
  "published_at": "2026-05-21T09:12:00.000Z",
  "updated_at": "2026-05-22T10:00:00.000Z"
}

Artikel in einer HTML-Vorlage

GET/v1/articles/:id/html

Gibt eine fertige HTML-Seite des veröffentlichten Artikels zurück, eingebettet in die Projektvorlage (text/html statt JSON). Unterstützt den Parameter language. Ideal zur direkten Einbettung auf einer Website.

terminal
curl https://public-api.rewriter.io/v1/articles/m93f7…/html \
  -H "Authorization: Bearer rw_live_3f8a…"

Webhooks

Webhooks senden signierte POST-Anfragen an deine URL, wenn in deinem Projekt Inhaltsereignisse auftreten. Konfiguriere sie im Dashboard im Bereich Konto → API & Integrationen.

Du kannst sie auch programmatisch registrieren, allein mit einem API-Schlüssel - ohne Schritt im Dashboard. Siehe Webhook-Abonnements.

Verfügbare Ereignisse

  • article.published - ein Artikel wurde veröffentlicht.
  • article.scheduled - ein Artikel wurde zur Veröffentlichung geplant.
  • article.unpublished - die Veröffentlichung eines Artikels wurde zurückgenommen.
  • article.archived - ein Artikel wurde archiviert.
  • article.restored - ein Artikel wurde aus dem Archiv wiederhergestellt.
  • article.translated - eine Artikelübersetzung wurde veröffentlicht.
  • topic.created - ein neues Thema wurde erstellt.
  • headline.created - neue Artikelvorschläge (Überschriften) wurden generiert.

Anfragetext

Jede Anfrage enthält einen JSON-Umschlag mit id (die Zustellungs-ID - nutze sie zur Deduplizierung), event, created_at, project_id und data mit den Ereignisdetails:

POST (webhook)
{
  "id": "whd_4f2a…",
  "event": "article.published",
  "created_at": "2026-05-21T09:12:00.000Z",
  "project_id": "k17a9c…",
  "data": {
    "id": "m93f7…",
    "title": "10 sposobów na lokalne SEO",
    "slug": "10-sposobow-na-lokalne-seo",
    "language": "pl",
    "status": "published",
    "topic_id": "j57b2…",
    "category": {
      "id": "k20a1…",
      "name": "Pielęgnacja ogrodu",
      "slug": "pielegnacja-ogrodu"
    },
    "seo_score": 96,
    "readability_score": 72,
    "fact_check_status": "passed",
    "published_at": "2026-05-21T09:12:00.000Z",
    "updated_at": "2026-05-21T09:12:00.000Z"
  }
}

Signaturprüfung

Jede Anfrage enthält den Header X-Rewriter-Webhook-Signature mit einer HMAC-SHA256-Signatur über den Zeitstempel (Header X-Rewriter-Webhook-Timestamp), einen Punkt und den Anfragetext im Format sha256=<hex>. Berechne sie mit deinem Secret neu und vergleiche zeitkonstant.

verify (node)
const ts = req.headers["x-rewriter-webhook-timestamp"];
const sig = req.headers["x-rewriter-webhook-signature"];
const expected = "sha256=" + crypto
  .createHmac("sha256", WEBHOOK_SECRET)
  .update(ts + "." + rawBody)
  .digest("hex");
const ok = crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));

Wiederholungen und automatische Deaktivierung

Fehlgeschlagene Zustellungen werden mit zunehmendem Abstand wiederholt (bis zu 5 Versuche), wobei bei jedem Versuch dieselbe Zustellungs-ID gesendet wird. Nach vielen aufeinanderfolgenden Fehlern wird der Webhook automatisch deaktiviert - aktiviere ihn im Dashboard erneut.

Webhook-Abonnements

Du kannst Webhook-Callbacks programmatisch registrieren und entfernen, allein mit einem API-Schlüssel - ohne Schritt im Dashboard. Diese Endpunkte treiben die sofortigen Trigger unserer Zapier- und Make.com-Apps an und lassen sich auch in deiner eigenen Integration nutzen.

POST und GET setzen zusätzlich einen Tarif mit Webhooks voraus - andernfalls antworten sie mit 403 forbidden. DELETE wird allein über den API-Schlüssel autorisiert, sodass das Entfernen eines Abonnements auch nach einem Tarifwechsel funktioniert.

Abonnement anlegen

POST/v1/webhooks

Registriert eine Callback-URL für genau ein Ereignis und liefert das Abonnement-Objekt mit Status 201 zurück (ohne data-Hülle). Speichere die zurückgegebene id - du übergibst sie beim Löschen des Abonnements.

Anfragetext

  • target_url - erforderlich. Eine HTTPS-Callback-URL auf einem der erlaubten Hosts.
  • event - erforderlich. Ein Ereignis aus der Liste oben.
terminal
curl -X POST https://public-api.rewriter.io/v1/webhooks \
  -H "Authorization: Bearer rw_live_3f8a…" \
  -H "Content-Type: application/json" \
  -d '{"target_url":"https://hook.eu2.make.com/abc123","event":"article.published"}'
201 Created
{
  "id": "n41c8…",
  "event": "article.published",
  "target_url": "https://hook.eu2.make.com/abc123",
  "status": "enabled"
}

Abonnement-Objekt

  • id - die Abonnement-ID - übergib sie an DELETE.
  • event - das Ereignis, für das das Abonnement registriert ist.
  • target_url - die registrierte Callback-URL.
  • status - enabled oder disabled - ein Abonnement wird nach wiederholt fehlgeschlagenen Zustellungen automatisch deaktiviert.

Erlaubte target_url-Hosts

target_url muss eine HTTPS-Hook-URL einer Automatisierungsplattform auf einem dieser Hosts sein:

  • hooks.zapier.com - Zapier Catch-Hook-URLs.
  • hook.make.com, hook.<zone>.make.com - Make.com-Webhooks, zum Beispiel hook.eu2.make.com.

Jeder andere Host, eine Nicht-HTTPS-URL, eine URL mit Zugangsdaten sowie private, Loopback- oder Metadaten-Adressen werden mit 400 bad_request abgelehnt.

Dieselbe Kombination aus target_url und event erneut zu senden erzeugt kein Duplikat: Das bestehende Abonnement wird reaktiviert und mit derselben id zurückgegeben. Ein Projekt kann bis zu 20 Abonnements pro Plattform halten.

Abonnements auflisten

GET/v1/webhooks

Liefert die mit diesem API-Schlüssel in diesem Projekt erstellten Abonnements. Abonnements anderer Schlüssel und im Dashboard konfigurierte Webhooks werden nie zurückgegeben.

GET /v1/webhooks
{
  "data": [
    {
      "id": "n41c8…",
      "event": "article.published",
      "target_url": "https://hook.eu2.make.com/abc123",
      "status": "enabled"
    }
  ]
}

Abonnement löschen

DELETE/v1/webhooks/:id

Löscht das Abonnement mit der angegebenen id. Idempotent: eine unbekannte, bereits gelöschte oder fremde id liefert 200 mit deleted: false statt 404, sodass das Aufräumen nie fehlschlägt.

DELETE /v1/webhooks/n41c8…
{
  "id": "n41c8…",
  "deleted": true
}

Fehler

  • 400 bad_request - target_url oder event fehlt, unbekanntes Ereignis oder eine target_url außerhalb der erlaubten Hosts.
  • 401 unauthorized - fehlender oder ungültiger API-Schlüssel.
  • 403 forbidden - der Tarif enthält keine Webhooks oder das Limit von 20 Abonnements ist erreicht.

Diese Antworten enthalten dieselben Header X-RateLimit-Limit, X-RateLimit-Remaining und X-RateLimit-Reset wie die Lese-Endpunkte.