Orova

/ Developers guide

Publishing via API
on any website.

How to build your own endpoint so Orova can publish finished articles to a site that does not run WordPress.

Orova publishes finished articles to WordPress out of the box. If your website is not WordPress — a custom CMS, a headless setup, a static site, or your own backend — you can still let Orova publish automatically by accepting articles over a small API. You write one HTTP endpoint; Orova calls it every time it finishes an article. This guide is for a developer and describes the full request contract.

/ Overview

How it works

When Orova finishes writing an article for a keyword, it sends a single HTTP POST request to the endpoint URL you registered. The request body is JSON and contains the whole article. Your endpoint creates the post on your side and replies with the final, public URL of the article. Orova saves that URL as the published link, just as it would for a WordPress post. Use this when you want hands-off publishing on a site that is not WordPress, or when you prefer to keep full control of how posts are stored.

/ Setup

Setting it up — five steps

  • 1

    Turn on “Connect via API” in your project. Open your project (Projects → your project → Connections). Next to the WordPress card you will find a “Connect via API” option. Enable it and Orova shows you two things: the endpoint URL field — where you paste your own URL — and a generated secret. Keep that secret safe; you will need it in step 3.

  • 2

    Build an endpoint that accepts POST. On your own site or server, create a route that listens for HTTP POST with a JSON body. This is the URL you paste back into the project Connections screen. Orova calls it once for every article it finishes.

  • 3

    Verify the Bearer token on every request. Every request from Orova carries an Authorization header in the form “Bearer <secret>”, using the exact secret shown in your project. Compare it against your stored copy and reject anything that does not match — this is what stops anyone else from posting to your site.

  • 4

    Create the article from the payload. Read the JSON body and create a post in your CMS or database: use title, slug and content_html for the article itself, excerpt as the meta description, featured_image_url as the cover image, and keyword / lang / published_at as metadata.

  • 5

    Return the live URL of the article. Respond with HTTP 200 or 201 and a JSON body of { "url": "https://yoursite.com/the-new-article" }. Orova stores that URL as the published link for the article. If you return a non-2xx status, or omit the url field, Orova treats the publish as failed.

/ Contract

The request Orova sends

Each finished article arrives as one request shaped like this:

POST <your endpoint URL>

Headers:
  Content-Type: application/json
  Authorization: Bearer <secret>     # the secret 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:00Z"  # ISO 8601 UTC
  }

/ Reference

Payload fields

Every field below is present in the JSON body of each request.

FieldTypeDescription
titlestringThe article headline.
slugstringURL-friendly identifier suggested for the post.
content_htmlstringThe full article body as ready-to-publish HTML.
excerptstringA short summary, intended for the meta description.
featured_image_urlstring | nullURL of the cover image, or null when there is none.
keywordstringThe target SEO keyword the article was written for.
langstringLanguage as an ISO code, e.g. "en" or "vi".
published_atstringIntended publish time, ISO 8601 in UTC.

/ Contract

The response you must return

Once you have created the post, reply with an HTTP 200 or 201 status and this JSON body:

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

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

Orova stores that url as the published link for the article. If your endpoint returns any non-2xx status, or a body without a url field, Orova treats the publish as failed and marks the article accordingly so you can retry it.

/ Example

Code example

A minimal receiving endpoint in Node.js with Express. The same four steps — verify the token, read the payload, create the post, return the URL — apply in any language or framework.

// 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. Read the payload Orova sent.
  const {
    title, slug, content_html, excerpt,
    featured_image_url, keyword, lang, published_at,
  } = req.body;

  // 3. 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,
  });

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

app.listen(3000);

/ Security

Security notes

  • Always verify the Bearer token. Your endpoint is a public URL — anyone could call it. The Authorization header is the only thing that proves a request really came from Orova, so reject every request whose token does not exactly match your stored secret.
  • Serve the endpoint over HTTPS. The secret travels in a header. HTTPS keeps it from being read in transit.
  • Keep the secret out of your code. Store it in an environment variable or a secrets manager, never hard-coded in a file you commit. If it is ever exposed, regenerate it from Project → Connections.
  • Treat content_html as content, not as trusted markup. Store and render it the same careful way you would any article body in your CMS.

/ Wrapping up

That is the whole contract

With the endpoint live and registered in your project, Orova publishes to your site automatically — exactly as it does for WordPress users. Each article it finishes lands on your server, becomes a post, and its public URL flows back into Reports and Analysis so you can track how it performs.

← Back to the guide library

/ Need a hand?

Stuck wiring up your endpoint? Open the Support section inside your workspace, or send us a message.