OROVA.VN — BIZ AI AGENT

/ Gabay para sa developer

Paglalathala sa pamamagitan ng API sa anumang website.

Paano bumuo ng sariling endpoint para mailathala ng Orova ang mga tapos na article sa site na hindi WordPress.

Naglalathala ang Orova ng mga tapos na article sa WordPress agad-agad. Kung ang iyong website ay hindi WordPress — custom CMS, headless setup, static site, o sariling backend — puwede mo pa ring hayaang kusang maglathala ang Orova sa pagtanggap ng mga article sa isang maliit na API. Sumulat ka ng isang HTTP endpoint; tinatawag ito ng Orova tuwing may natapos na article. Para sa developer ang gabay na ito at inilalarawan nito ang buong request contract.

/ Overview

Paano ito gumagana

Kapag natapos ng Orova ang pagsulat ng article para sa isang keyword, nagpapadala ito ng isang HTTP POST request sa endpoint URL na inirehistro mo. JSON ang request body at nilalaman nito ang buong article. Gagawin ng iyong endpoint ang post sa panig mo at sasagot ng final at pampublikong URL ng article. Itatago ng Orova ang URL na iyon bilang published link, tulad ng sa WordPress post. Gamitin ito kapag gusto mo ng hands-off na paglalathala sa site na hindi WordPress, o kapag gusto mong ikaw ang may buong kontrol sa pag-iimbak ng mga post.

/ Setup

Pag-set up — anim na hakbang

  • 1

    I-on ang “Kumonekta sa pamamagitan ng API” sa iyong project. Buksan ang iyong project (Mga Proyekto → iyong project → Mga Koneksyon). Katabi ng WordPress card ay may Kumonekta sa pamamagitan ng API na card. Ilagay doon ang URL ng iyong endpoint. Opsyonal ang secret key field: iwanang blangko at gagawa ang Orova ng isa, o i-paste ang key na gamit na ng iyong site. Pagka-save, ipapakita ang key sa card kasama ang Kopyahin na button. Iisang target lang ang pinaglalathalaan ng isang project — kapag kumonekta sa API, naka-lock ang WordPress button, at ganoon din pabaliktad.

  • 2

    Bumuo ng endpoint na tumatanggap ng POST. Sa sarili mong site o server, gumawa ng route na nakikinig sa HTTP POST na may JSON body. Ito ang URL na ipe-paste mo pabalik sa Ikonekta screen ng project. Tinatawag ito ng Orova nang isang beses para sa bawat natapos na article.

  • 3

    I-verify ang Bearer token sa bawat request. May Authorization header ang bawat request mula sa Orova sa anyong “Bearer <secret>”, gamit ang eksaktong secret key na nasa iyong project. Ikumpara ito sa naka-store mong kopya at tanggihan ang anumang hindi tugma — ito ang pumipigil sa iba na mag-post sa iyong site.

  • 4

    Gawin ang article mula sa payload. Basahin ang JSON body at gumawa ng post sa iyong CMS o database: gamitin ang title, slug at content_html para sa mismong article, excerpt bilang meta description, featured_image_url bilang cover image, at keyword / lang / published_at bilang metadata.

  • 5

    Ibalik ang live URL ng article. Sumagot ng HTTP 200 o 201 at JSON body na { "url": "https://yoursite.com/the-new-article" }. Itatago ng Orova ang URL na iyon bilang published link ng article. Kung magbabalik ka ng non-2xx status, o walang url field, ituturing ng Orova na bigo ang paglalathala.

  • 6

    Hawakan ang update request mula sa Optimize engine. Kapag may action = "update" ang body, hanapin ang kasalukuyang post gamit ang target_url (o slug) at palitan ang title, content_html at excerpt nito sa mismong lugar — huwag baguhin ang URL. Sumagot ng 200 na may { "url": ... } na tumuturo sa parehong post. Ang mga endpoint na hindi pa ito hinahawakan ay magpapa-report lang sa Orova na bigo ang optimization; patuloy na gumagana ang paglalathala ng bagong article.

/ Contract

Ang request na ipinapadala ng Orova

Dumarating ang bawat natapos na article bilang isang request na ganito ang anyo:

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.

/ Reference

Mga payload field

Mga field ng publish (bagong article) request. Ginagamit din ng delete at update request ang parehong endpoint na may mas maliit na body na ipinapakita sa sarili nilang seksyon sa ibaba.

FieldUriPaglalarawan
titlestringAng headline ng article.
slugstringURL-friendly identifier suggested for the post.
content_htmlstringAng buong body ng article bilang HTML na handang ilathala.
excerptstringMaikling buod, para sa meta description.
featured_image_urlstring | nullURL ng cover image, o null kapag wala.
keywordstringAng target na SEO keyword na pinagsulatan ng article.
langstringLanguage as an ISO code, e.g. "en" or "vi".
published_atstringAng oras na ipinadala ng Orova ang article, ISO 8601 sa UTC, walang timezone suffix.
statusstring | undefinedOpsyonal. "draft" para hindi ilathala ang article; "publish", o walang value, para ilathala ito.
actionstring | undefinedWala sa bagong article. Ang "delete" ay hiling na alisin ang isang post; ang "update" (ipinapadala ng Optimize engine) ay hiling na palitan ang kasalukuyang post sa mismong lugar.
target_urlstringKasama lang ng action = "update": ang live URL ng post na papalitan. Huwag baguhin ang URL.
idnumber | undefinedOnly sent when Orova knows your post id (from `list` or `get`): match on it before `target_url`.

Hindi isinasama sa body ang mga opsyonal na field kapag walang ipapadala — hindi nagpapadala ang Orova ng null, kaya basahin ang mga ito nang maingat. Opsyonal din ang status: ginagawang draft ng "draft" ang article, habang agad itong inilalathala ng "publish" o kapag walang status.

/ Contract

Ang response na dapat mong ibalik

Kapag nagawa mo na ang post, sumagot ng HTTP 200 o 201 status at ng JSON body na ito:

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

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

Itatago ng Orova ang url na iyon bilang published link ng article. Kung magbabalik ang iyong endpoint ng anumang non-2xx status, o body na hindi JSON object na may url field, ituturing ng Orova na bigo ang paglalathala at mamarkahan ang article para masubukan mo ulit. Sumagot sa loob ng 60 segundo — pagkatapos noon, puputulin ng Orova ang request (pareho para sa publish, update at delete).

/ Example

Code example

Isang minimal na receiving endpoint sa Node.js gamit ang Express. Pareho ang mga hakbang sa anumang wika o framework — i-verify ang token, mag-branch ayon sa action (update / delete), gawin o baguhin ang post, ibalik ang URL.

// 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);

/ Contract — update

Pag-update ng article (I-optimize)

Isinusulat muli ng Optimize engine ng Orova ang mga article na live na — bagong datos, mas magandang title, pinagsamang content — saka pinapalitan ang kasalukuyang post sa mismong lugar, nang hindi binabago ang URL. Pupunta ang request sa parehong endpoint URL, bilang POST na may parehong 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.

Hanapin ang post gamit ang target_url (kung wala, gamitin ang slug), palitan ang title, body at meta description nito, panatilihin ang URL, saka sumagot ng 200 na may { "url": "<same post URL>" }. Anumang non-2xx status, o body na walang url, ay magpapamarka sa Orova na bigo ang optimization (hindi ito gumagawa ng duplicate na post). Ang mga endpoint na hindi pa ito naipapatupad ay patuloy na naglalathala ng bagong article — kailangan lang ang update kapag ginamit mo na ang I-optimize na screen.

Mula Agosto 29, puwede ring may id ang update body (itugma muna rito bago ang target_url), featured_image_url para sa bagong cover image, at status na "publish" o "draft". Opsyonal ang tatlo; kapag walang laman, inaalis ang mga ito sa body, hindi ipinapadala bilang null.

/ Contract — Visual Editor

Pagbasa ng article (required)

Kailangang mabasa ng Orova ang mga article na nasa site mo na — para iwasan ang duplicate na paksa, magdagdag ng internal link at i-optimize ang mga lumang post. Magdagdag ng dalawa pang action sa parehong endpoint URL, gamit ang parehong Bearer token: ibinabalik ng list ang iyong mga article, ibinabalik ng get ang buo ng isa sa mga ito.

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" }

Hanggang 500 ang limit at nauuna ang pinakabagong article. Para sa get, sabay na ipinapadala ng Orova ang id, target_url at slug — itugma sa alinmang makilala mo, sa ganoong pagkakasunod. Kapag walang tugma, sumagot ng 404 na may { "ok": false, "err": "not_found" }. Opsyonal ang excerpt sa list (hanggang 300 character). Required: Tinatawag ng Orova ang list para malaman kung aling article ang mayroon na (para iwasan ang duplicate, magdagdag ng internal link at i-analyze ang buong site) at tinatawag ang get para basahin ang isang article kapag ino-optimize ito. Kung hindi sasagutin ng iyong site ang dalawang action na ito, walang internal link ang mga bagong article at hindi mao-optimize ang mga luma.

/ Contract — Visual Editor

Pag-upload ng larawan (Visual Editor)

Kapag nag-drop ka ng larawan sa Visual Editor, ipinapadala ito ng Orova sa parehong endpoint URL bilang base64 sa loob ng JSON body — walang multipart, walang pangalawang URL na kailangang i-secure.

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
  }

Tanggapin lang ang image/* at tanggihan ang anumang lampas sa 15 MB. I-store ang file, saka sumagot ng absolute URL ng larawan: masisira ang article kapag relative path at ipinakita ito sa ibang lugar. Para lang sa Visual Editor ang action na ito.

/ Contract — delete

Pag-delete ng article

Kapag nag-alis ang user ng published article sa loob ng Orova (mula sa Magsulat o Mga Ulat na screen), hihilingin ng Orova sa iyong site na i-delete din ito. Pupunta ang request sa parehong endpoint URL, bilang POST na may parehong Bearer token — ang body lang ang pinagkaiba:

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
  }

Hanapin ang post gamit ang url (kung wala, gamitin ang slug), alisin o i-unpublish ito, saka sumagot ng 200 at { "deleted": true } — gumagana rin ang 204 na walang laman. Kung wala na ang post, sumagot ng 404 at ituturing ito ng Orova na na-delete na. Ang pagbabalik ng { "deleted": false } ay nagsasabi sa Orova na hindi naalis ang post. Walang action field ang mga karaniwang publish request, kaya patuloy na gumagana ang mga kasalukuyang endpoint — opsyonal ang delete pero inirerekomenda.

/ Seguridad

Mga security note

  • Laging i-verify ang Bearer token. Pampublikong URL ang iyong endpoint — kahit sino ay puwedeng tumawag dito. Ang Authorization header lang ang nagpapatunay na talagang galing sa Orova ang request, kaya tanggihan ang bawat request na ang token ay hindi eksaktong tugma sa naka-store mong secret.
  • Patakbuhin ang endpoint sa HTTPS. Dumadaan sa header ang secret. Pinipigilan ng HTTPS na mabasa ito habang ipinapadala.
  • Huwag ilagay ang secret sa iyong code. I-store ito sa environment variable o secrets manager, huwag i-hard-code sa file na kino-commit mo. Kapag nalantad ito, gumawa ng bago mula sa Proyekto → Mga Koneksyon.
  • Ituring ang content_html bilang content, hindi bilang pinagkakatiwalaang markup. I-store at i-render ito nang may parehong ingat tulad ng anumang article body sa iyong CMS.

/ Pagtatapos

Iyan na ang buong contract

Kapag live na ang endpoint at nakarehistro sa iyong project, kusang maglalathala ang Orova sa iyong site — gaya ng ginagawa nito para sa mga WordPress user. Bawat natapos na article ay dumarating sa iyong server, nagiging post, at bumabalik ang pampublikong URL nito sa Mga Ulat at Analysis para masubaybayan mo ang performance nito.

← Bumalik sa library ng gabay

/ Kailangan ng tulong?

Nahihirapang ikonekta ang iyong endpoint? Buksan ang Suporta sa loob ng iyong workspace, o magpadala sa amin ng mensahe.