OROVA.VN — BIZ AI AGENT

/ Anleitung für Entwickler

Veröffentlichen über API auf jeder Website.

So bauen Sie Ihren eigenen Endpoint, damit Orova Artikel auf einer Website ohne WordPress veröffentlichen kann.

Orova veröffentlicht fertige Artikel von Haus aus auf WordPress. Wenn Ihre Website kein WordPress ist — ein eigenes CMS, ein Headless-System, eine statische Website oder Ihr eigenes Backend —, können Sie Orova trotzdem automatisch veröffentlichen lassen, indem Sie Artikel über eine kleine API annehmen. Sie schreiben einen HTTP-Endpoint; jedes Mal, wenn ein Artikel fertig ist, ruft Orova ihn auf. Diese Anleitung richtet sich an Entwickler und beschreibt den vollständigen Request-Vertrag.

/ Überblick

So funktioniert es

Sobald Orova einen Artikel für ein Keyword fertig geschrieben hat, sendet es genau einen HTTP-POST-Request an die von Ihnen hinterlegte Endpoint-URL. Der Request-Body ist JSON und enthält den gesamten Artikel. Ihr Endpoint legt den Beitrag bei Ihnen an und antwortet mit der endgültigen, öffentlichen URL des Artikels. Orova speichert diese URL als veröffentlichten Link, genau wie bei einem WordPress-Beitrag. Nutzen Sie dies, wenn Sie auf einer Website ohne WordPress automatisch veröffentlichen oder selbst bestimmen möchten, wie Beiträge gespeichert werden.

/ Einrichtung

Einrichtung — sechs Schritte

  • 1

    „Über API verbinden“ im Projekt aktivieren. Öffnen Sie Ihr Projekt (Projekte → Ihr Projekt → Verbindungen). Neben der WordPress-Karte gibt es die Karte Über API verbinden. Geben Sie dort die URL Ihres Endpoints ein. Das Feld für den geheimen Schlüssel ist optional: Lassen Sie es leer, erzeugt Orova einen Schlüssel, oder fügen Sie einen Schlüssel ein, den Ihre Website bereits verwendet. Nach dem Speichern erscheint der Schlüssel auf der Karte mit einer Schaltfläche „Kopieren“. Jedes Projekt veröffentlicht nur an ein Ziel — wenn Sie über API verbinden, wird die WordPress-Schaltfläche gesperrt, und umgekehrt.

  • 2

    Einen Endpoint bauen, der POST annimmt. Legen Sie auf Ihrer Website oder Ihrem Server eine Route an, die auf HTTP POST mit JSON-Body hört. Genau diese URL fügen Sie im Bildschirm „Verbindungen“ des Projekts ein. Orova ruft sie für jeden fertigen Artikel genau einmal auf.

  • 3

    Den Bearer-Token bei jedem Request prüfen. Jeder Request von Orova trägt einen Authorization-Header in der Form „Bearer <secret>“ mit genau dem geheimen Schlüssel, der in Ihrem Projekt angezeigt wird. Vergleichen Sie ihn mit Ihrer gespeicherten Kopie und weisen Sie jeden nicht passenden Request ab — nur so verhindern Sie, dass Fremde Beiträge auf Ihrer Website veröffentlichen.

  • 4

    Den Artikel aus dem Payload erstellen. Lesen Sie den JSON-Body und legen Sie einen Beitrag in Ihrem CMS oder Ihrer Datenbank an: title, slug und content_html für den Artikel selbst, excerpt als Meta-Beschreibung, featured_image_url als Titelbild und keyword / lang / published_at als Metadaten.

  • 5

    Die echte URL des Artikels zurückgeben. Antworten Sie mit HTTP 200 oder 201 und dem JSON-Body { "url": "https://ihre-website.de/neuer-artikel" }. Orova speichert diese URL als veröffentlichten Link des Artikels. Geben Sie einen Status außerhalb von 2xx zurück oder fehlt das Feld url, wertet Orova die Veröffentlichung als fehlgeschlagen.

  • 6

    Update-Requests der Optimieren-Engine verarbeiten. Enthält der Body action = "update", suchen Sie den bestehenden Beitrag über target_url (oder slug) und überschreiben Sie title, content_html und excerpt direkt an Ort und Stelle — die URL bleibt unverändert. Antworten Sie mit 200 und { "url": ... }, das auf denselben Beitrag zeigt. Endpoints, die dies noch nicht verarbeiten, führen nur dazu, dass Orova die Optimierung als fehlgeschlagen meldet; das Veröffentlichen neuer Artikel funktioniert weiter wie bisher.

/ Vertrag

Der Request, den Orova sendet

Jeder fertige Artikel kommt als ein Request in dieser Form an:

POST <your endpoint URL>

Headers:
  Content-Type: application/json
  Authorization: Bearer <secret>     # the secret key shown in Project -> Connections
  User-Agent: Orova-SEO

Body (JSON):
  {
    "title": "...",                  # article headline
    "slug": "...",                   # URL-friendly identifier
    "content_html": "...",           # full article HTML
    "excerpt": "...",                # meta description
    "featured_image_url": "..." | null,
    "keyword": "...",                # target keyword
    "lang": "en",                    # ISO language code
    "published_at": "2026-05-17T09:00:00.482913",  # ISO 8601, UTC, no offset suffix
    "status": "draft"                # optional: "draft" keeps it unpublished
  }
  # Optional fields are left out of the body when empty — never sent as null.

/ Referenz

Payload-Felder

Felder eines Requests zum Veröffentlichen eines neuen Artikels. Lösch- und Update-Requests nutzen denselben Endpoint mit kleineren Bodys — siehe die jeweiligen Abschnitte unten.

FeldTypBeschreibung
titlestringDie Überschrift des Artikels.
slugstringURL-friendly identifier suggested for the post.
content_htmlstringDer vollständige Artikeltext als sofort veröffentlichbares HTML.
excerptstringEine kurze Zusammenfassung, gedacht als Meta-Beschreibung.
featured_image_urlstring | nullURL des Titelbilds oder null, wenn es keines gibt.
keywordstringDas SEO-Keyword, auf das der Artikel ausgerichtet ist.
langstringLanguage as an ISO code, e.g. "en" or "vi".
published_atstringDer Zeitpunkt, zu dem Orova den Artikel gesendet hat, ISO 8601 in UTC, ohne Zeitzonen-Suffix.
statusstring | undefinedOptional. "draft" belässt den Artikel als Entwurf; "publish" oder gar kein Wert veröffentlicht ihn sofort.
actionstring | undefinedFehlt bei neuen Artikeln. "delete" fordert Sie auf, einen Beitrag zu entfernen; "update" (von der Optimieren-Engine gesendet) fordert Sie auf, einen bestehenden Beitrag an Ort und Stelle zu überschreiben.
target_urlstringNur mit action = "update": die echte URL des zu überschreibenden Beitrags. Behalten Sie diese URL unverändert bei.
idnumber | undefinedOnly sent when Orova knows your post id (from `list` or `get`): match on it before `target_url`.

Optionale Felder ohne Inhalt lässt Orova komplett aus dem Body weg und sendet nie null — lesen Sie optionale Felder daher defensiv. Auch status ist optional: "draft" legt den Artikel als Entwurf an, "publish" oder gar kein status veröffentlicht ihn sofort.

/ Vertrag

Die Response, die Sie zurückgeben müssen

Sobald der Beitrag angelegt ist, antworten Sie mit HTTP-Status 200 oder 201 und diesem JSON-Body:

HTTP 200 (or 201)
Content-Type: application/json

{
  "url": "https://yoursite.com/published-article"
}

Orova speichert diese url als veröffentlichten Link des Artikels. Gibt Ihr Endpoint einen Status außerhalb von 2xx zurück oder ist der Body kein JSON-Objekt mit dem Feld url, wertet Orova die Veröffentlichung als fehlgeschlagen und markiert den Artikel, damit Sie es erneut versuchen können. Antworten Sie innerhalb von 60 Sekunden — danach bricht Orova den Request ab (gilt gleichermaßen für Veröffentlichen, Aktualisieren und Löschen).

/ Beispiel

Codebeispiel

Ein minimaler Empfangs-Endpoint in Node.js mit Express. Die Schritte sind in jeder Sprache und jedem Framework gleich: Token prüfen, nach action verzweigen (update / delete), Beitrag anlegen oder ändern, URL zurückgeben.

// Node.js / Express — a minimal receiving endpoint
import express from "express";

const app = express();
app.use(express.json({ limit: "5mb" }));

// The secret Orova generated for this project.
const OROVA_SECRET = process.env.OROVA_SECRET;

app.post("/orova/publish", async (req, res) => {
  // 1. Verify the Bearer token.
  const auth = req.get("authorization") || "";
  if (auth !== "Bearer " + OROVA_SECRET) {
    return res.status(401).json({ error: "unauthorized" });
  }

  // 2. Required: list your articles (duplicate check, internal links). action = "list".
  if (req.body.action === "list") {
    const posts = await listPosts(req.body.limit || 500); // newest first, 500 max
    // each post: { id, title, slug, link, date, modified, status, author, excerpt? }
    return res.status(200).json({ ok: true, posts });
  }

  // 3. Required: read one article in full (used when optimizing it). action = "get".
  if (req.body.action === "get") {
    const post = await findPost(req.body.id, req.body.target_url, req.body.slug);
    if (!post) return res.status(404).json({ ok: false, err: "not_found" });
    return res.status(200).json({ ok: true, post });
  }

  // 4. Visual Editor: store an image, answer with its absolute URL.
  if (req.body.action === "upload_image") {
    const { filename, mime, data_base64 } = req.body;
    if (!String(mime || "").startsWith("image/")) {
      return res.status(422).json({ error: "image files only" });
    }
    const bytes = Buffer.from(data_base64, "base64");
    if (bytes.length > 15 * 1024 * 1024) {
      return res.status(413).json({ error: "image too large" });
    }
    return res.status(200).json({ ok: true, url: await saveImage(filename, bytes) });
  }

  // 5. Delete requests: body carries action = "delete".
  if (req.body.action === "delete") {
    const removed = await deletePostByUrl(req.body.url, req.body.slug);
    if (!removed) return res.status(404).json({ deleted: true }); // already gone
    return res.status(200).json({ deleted: true });
  }

  // 6. Update requests: action = "update". Optional fields may be absent.
  if (req.body.action === "update") {
    const updated = await updatePost(req.body.id, req.body.target_url, {
      title: req.body.title,
      html: req.body.content_html,
      metaDescription: req.body.excerpt,
      coverImage: req.body.featured_image_url,  // optional
      status: req.body.status,                  // optional: "publish" | "draft"
    });
    if (!updated) return res.status(404).json({ error: "post not found" });
    return res.status(200).json({ url: updated.url });
  }

  // 7. New article: read the payload Orova sent.
  const {
    title, slug, content_html, excerpt,
    featured_image_url, keyword, lang, published_at, status,
  } = req.body;

  // 8. Create the article in your own CMS or database.
  const post = await createPost({
    title,
    slug,
    html: content_html,
    metaDescription: excerpt,
    coverImage: featured_image_url,
    keyword,
    lang,
    publishedAt: published_at,
    draft: status === "draft",   // status is optional; absent means publish now
  });

  // 9. Return 200/201 with the live URL.
  return res.status(201).json({
    url: "https://yoursite.com/" + post.slug,
  });
});

app.listen(3000);

/ Vertrag — Aktualisieren

Artikel aktualisieren (Optimieren)

Die Optimieren-Engine von Orova überarbeitet bereits veröffentlichte Artikel — aktualisierte Fakten, bessere Titel, zusammengeführte Inhalte — und überschreibt dann den bestehenden Beitrag an Ort und Stelle, die URL bleibt unverändert. Der Request geht an dieselbe Endpoint-URL, ebenfalls als POST mit demselben Bearer-Token:

POST <your endpoint URL>

Headers:
  Content-Type: application/json
  Authorization: Bearer <secret>
  User-Agent: Orova-SEO

Body (JSON):
  {
    "action": "update",          # always the literal string "update"
    "id": 123,                   # optional: post id, match on this first
    "target_url": "...",         # public URL of the post to overwrite (match next)
    "title": "...",              # new headline
    "slug": "...",               # slug fallback for matching, may be empty
    "content_html": "...",       # full new article body as HTML
    "excerpt": "...",            # new meta description
    "featured_image_url": "...", # optional: new cover image
    "status": "publish"          # optional: "publish" or "draft"
  }
  # Optional fields are left out of the body when empty — never sent as null.

Suchen Sie den Beitrag über target_url (sonst über slug), ersetzen Sie Titel, Text und Meta-Beschreibung, lassen Sie die URL unverändert und antworten Sie dann mit 200 und { "url": "<same post URL>" }. Ein Status außerhalb von 2xx oder ein Body ohne url führt dazu, dass Orova diese Optimierung als fehlgeschlagen markiert (Orova legt nie einen doppelten Beitrag an). Endpoints ohne diese Funktion veröffentlichen neue Artikel weiterhin normal — Sie müssen sie erst ergänzen, wenn Sie den Bildschirm „Optimieren“ nutzen.

Seit dem 29. August kann der Update-Body zusätzlich id enthalten (zuerst danach suchen, dann nach target_url), featured_image_url für ein neues Titelbild und status mit "publish" oder "draft". Alle drei sind optional; ohne Wert lässt Orova den Schlüssel weg und sendet nie null.

/ Vertrag — Visual Editor

Artikel lesen (erforderlich)

Orova muss die Artikel lesen können, die bereits auf Ihrer Website stehen — um doppelte Themen zu vermeiden, interne Links einzufügen und ältere Beiträge zu optimieren. Ergänzen Sie zwei weitere Actions auf derselben Endpoint-URL mit demselben Bearer-Token: list gibt Ihre Artikel zurück, get einen davon vollständig.

POST <your endpoint URL>     # same endpoint, same Bearer secret

Body (JSON):
  {
    "action": "list",            # always the literal string "list"
    "limit": 500                 # newest article first, 500 maximum
  }

Response — HTTP 200:
  {
    "ok": true,
    "posts": [
      {
        "id": 123,               # your own post id, reused by "get" and "update"
        "title": "...",
        "slug": "...",
        "link": "https://yoursite.com/the-article",
        "date": "2026-08-29",    # published date, YYYY-MM-DD
        "modified": "2026-08-29",
        "status": "publish",     # "publish" or "draft"
        "author": "...",
        "excerpt": "..."         # optional: short summary, 300 characters max
      }
    ]
  }
  # Required: Orova reads this list to avoid duplicate topics,
  # add internal links and analyze the whole site.
POST <your endpoint URL>

Body (JSON):
  {
    "action": "get",             # always the literal string "get"
    "id": 123,                   # match on this first
    "target_url": "...",         # then the public URL
    "slug": "..."                # then the slug
  }

Response — HTTP 200:
  {
    "ok": true,
    "post": {
      "id": 123,
      "title": "...",
      "slug": "...",
      "link": "https://yoursite.com/the-article",
      "content_html": "...",     # full article body as HTML
      "excerpt": "...",
      "featured_image_url": "...",
      "status": "publish"        # "publish" or "draft"
    }
  }

No such post — HTTP 404:
  { "ok": false, "err": "not_found" }

limit ist auf 500 begrenzt, der neueste Artikel steht zuerst. Bei get sendet Orova id, target_url und slug gemeinsam — suchen Sie nach dem, was Sie erkennen, in genau dieser Reihenfolge. Wird nichts gefunden, antworten Sie mit 404 und { "ok": false, "err": "not_found" }. excerpt in list ist optional (maximal 300 Zeichen). Erforderlich: Orova ruft list auf, um zu erfahren, welche Artikel es bereits gibt (um Dopplungen zu vermeiden, interne Links einzufügen und die gesamte Website zu analysieren), und get, um einen Artikel beim Optimieren zu lesen. Beantwortet Ihre Website diese beiden Actions nicht, erhalten neue Artikel keine internen Links und ältere Artikel lassen sich nicht optimieren.

/ Vertrag — Visual Editor

Bilder hochladen (Visual Editor)

Wenn Sie ein Bild in den Visual Editor ziehen, sendet Orova es an dieselbe Endpoint-URL als Base64 im JSON-Body — kein Multipart, keine zweite URL, die Sie absichern müssen.

POST <your endpoint URL>

Body (JSON):
  {
    "action": "upload_image",    # always the literal string "upload_image"
    "filename": "cover.png",     # original file name, extension included
    "mime": "image/png",         # image/* only
    "data_base64": "iVBORw0KGgo..."   # file bytes, base64, 15 MB maximum
  }

Response — HTTP 200 (or 201):
  {
    "ok": true,
    "url": "https://yoursite.com/uploads/cover.png"   # absolute URL
  }

Nehmen Sie nur image/* an und lehnen Sie alles über 15 MB ab. Speichern Sie die Datei und antworten Sie dann mit der absoluten URL des Bildes: Ein relativer Pfad zerstört den Artikel, sobald er an anderer Stelle angezeigt wird. Diese Action wird nur für den Visual Editor benötigt.

/ Vertrag — Löschen

Artikel löschen

Wenn ein Nutzer einen veröffentlichten Artikel direkt in Orova entfernt (im Bildschirm „Schreiben“ oder „Berichte“), bittet Orova Ihre Website, ihn ebenfalls zu löschen. Der Request geht an dieselbe Endpoint-URL, ebenfalls als POST mit demselben Bearer-Token — nur der Body ist anders:

POST <your endpoint URL>

Headers:
  Content-Type: application/json
  Authorization: Bearer <secret>
  User-Agent: Orova-SEO

Body (JSON):
  {
    "action": "delete",          # always the literal string "delete"
    "url": "...",                # public URL of the article to remove (match on this first)
    "slug": "...",               # slug fallback, may be empty
    "keyword": "..."             # the article's target keyword, for your logs
  }

Suchen Sie den Beitrag über url (sonst über slug), löschen Sie ihn oder heben Sie die Veröffentlichung auf und antworten Sie dann mit 200 und { "deleted": true } — ein leeres 204 funktioniert ebenfalls. Existiert der Beitrag nicht mehr, antworten Sie mit 404, und Orova betrachtet ihn als bereits gelöscht. Mit { "deleted": false } melden Sie, dass der Beitrag nicht entfernt wurde. Normale Veröffentlichungs-Requests enthalten nie ein Feld action, daher funktionieren bestehende Endpoints unverändert weiter — das Löschen umzusetzen ist optional, aber empfohlen.

/ Sicherheit

Sicherheitshinweise

  • Bearer-Token immer prüfen. Ihr Endpoint ist eine öffentliche URL — jeder kann ihn aufrufen. Der Authorization-Header ist das Einzige, was beweist, dass ein Request wirklich von Orova kommt. Weisen Sie daher jeden Request ab, dessen Token nicht exakt mit Ihrem gespeicherten Schlüssel übereinstimmt.
  • Endpoint über HTTPS betreiben. Der geheime Schlüssel wird im Header übertragen. HTTPS verhindert, dass er unterwegs mitgelesen wird.
  • Schlüssel nicht im Code ablegen. Bewahren Sie ihn in einer Umgebungsvariablen oder einem Secrets-Manager auf und schreiben Sie ihn nie fest in eine Datei, die Sie committen. Falls er doch einmal offengelegt wird, erzeugen Sie unter Projekt → Verbindungen einen neuen.
  • content_html als Inhalt behandeln, nicht als vertrauenswürdiges Markup. Speichern und rendern Sie ihn genauso sorgfältig wie jeden anderen Artikeltext in Ihrem CMS.

/ Zum Abschluss

Das ist der ganze Vertrag

Sobald der Endpoint läuft und im Projekt hinterlegt ist, veröffentlicht Orova automatisch auf Ihrer Website — genau wie für WordPress-Nutzer. Jeder fertige Artikel landet auf Ihrem Server, wird zu einem Beitrag, und seine öffentliche URL fließt zurück in Berichte und Analyse, damit Sie die Wirkung verfolgen können.

← Zurück zur Anleitungsbibliothek

/ Brauchen Sie Hilfe?

Der Endpoint lässt sich nicht anbinden? Öffnen Sie den Bereich Support in Ihrem Workspace oder senden Sie uns eine Nachricht.