/ ডেভেলপারদের জন্য নির্দেশিকা
API দিয়ে পোস্ট প্রকাশ যেকোনো ওয়েবসাইটে।
কীভাবে নিজের endpoint তৈরি করবেন যাতে Orova WordPress ছাড়া অন্য ওয়েবসাইটে পোস্ট প্রকাশ করতে পারে।
Orova শুরু থেকেই WordPress-এ পোস্ট প্রকাশ করে। আপনার ওয়েবসাইট যদি WordPress না হয় — নিজে বানানো CMS, headless সিস্টেম, স্ট্যাটিক সাইট বা নিজস্ব backend — তবুও ছোট একটি API দিয়ে আর্টিকেল গ্রহণ করে Orova-কে স্বয়ংক্রিয়ভাবে প্রকাশ করতে দিতে পারেন। আপনি একটি HTTP endpoint লেখেন; প্রতিবার একটি আর্টিকেল লেখা শেষ হলে Orova সেখানে কল করে। এই পেজ ডেভেলপারদের জন্য এবং পূর্ণ request চুক্তি বর্ণনা করে।
/ সংক্ষিপ্ত বিবরণ
কীভাবে কাজ করে
একটি কীওয়ার্ডের জন্য আর্টিকেল লেখা শেষ হলে Orova আপনার নিবন্ধিত endpoint URL-এ ঠিক একটি HTTP POST request পাঠায়। request-এর বডি JSON, যাতে পুরো আর্টিকেলটি থাকে। আপনার endpoint আপনার দিকে পোস্ট তৈরি করে, তারপর আর্টিকেলের চূড়ান্ত পাবলিক URL ফেরত দেয়। Orova সেই URL প্রকাশিত লিংক হিসেবে সংরক্ষণ করে, ঠিক WordPress পোস্টের মতো। WordPress নয় এমন ওয়েবসাইটে স্বয়ংক্রিয় প্রকাশ চাইলে, বা পোস্ট সংরক্ষণের পদ্ধতি নিজের নিয়ন্ত্রণে রাখতে চাইলে এই পদ্ধতি ব্যবহার করুন।
/ সেটআপ
সেটআপ — ছয় ধাপ
- 1
প্রজেক্টে “API দিয়ে সংযোগ” চালু করুন. আপনার প্রজেক্ট খুলুন (প্রজেক্ট → আপনার প্রজেক্ট → সংযোগ)। WordPress কার্ডের পাশে API দিয়ে সংযোগ কার্ড আছে। সেখানে আপনার endpoint-এর ঠিকানা লিখুন। গোপন কী-র ঘর ঐচ্ছিক: খালি রাখলে Orova নিজে একটি কী তৈরি করে, অথবা আপনার ওয়েবসাইটে ব্যবহৃত কী পেস্ট করুন। সংরক্ষণের পর কী কার্ডে কপি বোতামসহ সঙ্গে সঙ্গে দেখা যায়। প্রতিটি প্রজেক্ট শুধু এক জায়গায় প্রকাশ করে — API দিয়ে সংযুক্ত করলে WordPress সংযোগ বোতাম লক হয়ে যায়, এবং উল্টোটাও।
- 2
POST গ্রহণকারী একটি endpoint তৈরি করুন. আপনার ওয়েবসাইট বা সার্ভারে JSON বডিসহ HTTP POST শোনে এমন একটি route তৈরি করুন। এটিই সেই ঠিকানা যা আপনি প্রজেক্টের সংযোগ স্ক্রিনে পেস্ট করবেন। প্রতিটি আর্টিকেল লেখা শেষ হলে Orova সেখানে ঠিক একবার কল করে।
- 3
প্রতিটি request-এ Bearer token যাচাই করুন. Orova-র প্রতিটি request-এ “Bearer <secret>” আকারে Authorization হেডার থাকে, যা প্রজেক্টে দেখানো গোপন কী-র সাথে হুবহু মেলে। আপনার সংরক্ষিত কপির সাথে মিলিয়ে দেখুন এবং না মিললে সব request প্রত্যাখ্যান করুন — অপরিচিত কেউ যেন আপনার ওয়েবসাইটে পোস্ট দিতে না পারে, এটিই একমাত্র সুরক্ষা।
- 4
payload থেকে পোস্ট তৈরি করুন. JSON বডি পড়ে আপনার CMS বা ডেটাবেসে পোস্ট তৈরি করুন: আর্টিকেলের জন্য title, slug ও content_html, মেটা বিবরণ হিসেবে excerpt, কভার ছবি হিসেবে featured_image_url, এবং keyword / lang / published_at মেটাডেটা হিসেবে ব্যবহার করুন।
- 5
আর্টিকেলের আসল URL ফেরত দিন. HTTP 200 বা 201 এবং { "url": "https://yoursite.com/the-new-article" } JSON বডি দিয়ে উত্তর দিন। Orova সেই URL আর্টিকেলের প্রকাশিত লিংক হিসেবে সংরক্ষণ করে। 2xx-এর বাইরের কোড দিলে, বা url ফিল্ড না থাকলে, Orova সেই প্রকাশকে ব্যর্থ ধরে।
- 6
অপটিমাইজ ইঞ্জিনের আপডেট request সামলান. request বডিতে action = "update" থাকলে, target_url (বা slug) দিয়ে পুরোনো পোস্ট খুঁজে title, content_html ও excerpt জায়গাতেই ওভাররাইট করুন — URL অপরিবর্তিত রাখুন। একই পোস্টকে নির্দেশ করা { "url": ... } সহ 200 দিন। যে endpoint এখনো এটি সামলায় না, তাতে Orova শুধু অপটিমাইজেশনকে ব্যর্থ দেখাবে; নতুন পোস্ট প্রকাশ আগের মতোই চলবে।
/ চুক্তি
Orova যে request পাঠায়
প্রতিটি সমাপ্ত আর্টিকেল এমন একটি request হিসেবে আসে:
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./ রেফারেন্স
payload-এর ফিল্ড
নতুন আর্টিকেল প্রকাশের request-এর ফিল্ড। মুছে ফেলা ও আপডেটের request একই endpoint ব্যবহার করে, বডি ছোট — নিচে প্রতিটির নিজস্ব অংশ দেখুন।
| ফিল্ড | ধরন | বিবরণ |
|---|---|---|
| title | string | আর্টিকেলের শিরোনাম। |
| slug | string | URL-friendly identifier suggested for the post. |
| content_html | string | সরাসরি প্রকাশযোগ্য HTML আকারে আর্টিকেলের পুরো বডি। |
| excerpt | string | সংক্ষিপ্ত সারাংশ, মেটা বিবরণ হিসেবে ব্যবহারের জন্য। |
| featured_image_url | string | null | কভার ছবির URL, অথবা ছবি না থাকলে null। |
| keyword | string | আর্টিকেলটি যে লক্ষ্য SEO কীওয়ার্ডের জন্য লেখা। |
| lang | string | Language as an ISO code, e.g. "en" or "vi". |
| published_at | string | Orova যে মুহূর্তে আর্টিকেল পাঠিয়েছে, UTC-তে ISO 8601, টাইমজোন প্রত্যয় ছাড়া। |
| status | string | undefined | ঐচ্ছিক। "draft" আর্টিকেলকে খসড়া রাখে; "publish" বা কোনো মান না দিলে সঙ্গে সঙ্গে প্রকাশ হয়। |
| action | string | undefined | নতুন আর্টিকেলে থাকে না। "delete" মানে একটি পোস্ট সরাতে বলা; "update" (অপটিমাইজ ইঞ্জিন পাঠায়) মানে বিদ্যমান পোস্ট জায়গাতেই ওভাররাইট করতে বলা। |
| target_url | string | শুধু action = "update"-এর সাথে: যে পোস্ট ওভাররাইট করতে হবে তার আসল URL। এই URL অপরিবর্তিত রাখুন। |
| id | number | undefined | Only sent when Orova knows your post id (from `list` or `get`): match on it before `target_url`. |
ঐচ্ছিক ফিল্ডে পাঠানোর কিছু না থাকলে Orova পুরো কী-টিই বাদ দেয়, null পাঠায় না — তাই সব ঐচ্ছিক ফিল্ড সতর্কভাবে পড়ুন। status-ও ঐচ্ছিক: "draft" খসড়া হিসেবে আর্টিকেল তৈরি করে, আর "publish" বা status না থাকলে সঙ্গে সঙ্গে প্রকাশ হয়।
/ চুক্তি
আপনাকে যে response ফেরত দিতে হবে
পোস্ট তৈরি হলে HTTP 200 বা 201 কোড এবং এই JSON বডি দিয়ে উত্তর দিন:
HTTP 200 (or 201)
Content-Type: application/json
{
"url": "https://yoursite.com/published-article"
}Orova সেই url আর্টিকেলের প্রকাশিত লিংক হিসেবে সংরক্ষণ করে। আপনার endpoint 2xx-এর বাইরের কোড দিলে, বা response বডি url ফিল্ডসহ JSON object না হলে, Orova প্রকাশকে ব্যর্থ ধরে এবং আবার চালানোর জন্য আর্টিকেলটি চিহ্নিত করে। 60 সেকেন্ড-এর মধ্যে উত্তর দিন — এর বেশি হলে Orova request বিচ্ছিন্ন করে (প্রকাশ, আপডেট ও মুছে ফেলা সবক্ষেত্রে প্রযোজ্য)।
/ উদাহরণ
নমুনা কোড
Express-সহ Node.js-এ লেখা একটি ন্যূনতম গ্রহণকারী endpoint। যেকোনো ভাষা বা framework-এ ধাপ একই: token যাচাই, action অনুযায়ী শাখা (update / delete), পোস্ট তৈরি বা পরিবর্তন, তারপর 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);/ চুক্তি — আপডেট
পোস্ট আপডেট (অপটিমাইজ)
Orova-র অপটিমাইজ ইঞ্জিন ইতিমধ্যে লাইভ থাকা আর্টিকেল নতুন করে লেখে — তথ্য হালনাগাদ, শিরোনাম সংশোধন, কনটেন্ট একত্রীকরণ — তারপর পুরোনো পোস্ট জায়গাতেই, URL অপরিবর্তিত রেখে ওভাররাইট করে। request যায় একই endpoint URL-এ, একই Bearer token-সহ POST হিসেবে:
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.target_url দিয়ে পোস্ট খুঁজুন (না পেলে slug দিয়ে), শিরোনাম, বডি ও মেটা বিবরণ বদলান, URL অপরিবর্তিত রাখুন, তারপর { "url": "<same post URL>" } সহ 200 দিন। 2xx-এর বাইরের কোড, বা url ছাড়া response বডি দিলে Orova সেই অপটিমাইজেশনকে ব্যর্থ চিহ্নিত করে (Orova কখনো ডুপ্লিকেট পোস্ট তৈরি করে না)। যে endpoint এখনো এটি করেনি তা স্বাভাবিকভাবে নতুন পোস্ট প্রকাশ করে — শুধু অপটিমাইজ স্ক্রিন ব্যবহার করলে তবেই যোগ করতে হবে।
29/8 থেকে আপডেটের বডিতে id (আগে id দিয়ে খুঁজুন, তারপর target_url), কভার ছবি বদলাতে featured_image_url, এবং "publish" বা "draft" মানসহ status থাকতে পারে। তিনটিই ঐচ্ছিক; মান না থাকলে Orova কী-টি বাদ দেয়, null পাঠায় না।
/ চুক্তি — Visual Editor
পোস্ট পড়া (বাধ্যতামূলক)
Orova-কে আপনার ওয়েবসাইটে থাকা পোস্টগুলো পড়তে পারতে হবে — যাতে একই বিষয় দুবার না লেখে, ইন্টারনাল লিংক যোগ করে ও পুরোনো পোস্ট অপটিমাইজ করে। একই endpoint URL-এ, একই Bearer token-সহ আরও দুটি action যোগ করুন: list পোস্টের তালিকা দেয়, get একটি পোস্ট পুরোটা দেয়।
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 সর্বোচ্চ 500, নতুনতম পোস্ট প্রথমে। get-এর জন্য Orova একসাথে id, target_url ও slug পাঠায় — যেটি চিনতে পারেন সেটি দিয়ে, এই ক্রমে খুঁজুন। পোস্ট না পেলে { "ok": false, "err": "not_found" } সহ 404 দিন। list-এ excerpt ঐচ্ছিক (সর্বোচ্চ 300 অক্ষর)। বাধ্যতামূলক: কোন পোস্ট আগে থেকে আছে জানতে Orova list কল করে (ডুপ্লিকেট এড়াতে, ইন্টারনাল লিংক যোগ করতে, পুরো সাইট বিশ্লেষণ করতে) এবং অপটিমাইজের সময় কনটেন্ট পড়তে get কল করে। ওয়েবসাইট এই দুটি action-এর উত্তর না দিলে নতুন পোস্টে ইন্টারনাল লিংক থাকবে না এবং পুরোনো পোস্ট অপটিমাইজ করা যাবে না।
/ চুক্তি — Visual Editor
ছবি আপলোড (Visual Editor)
Visual Editor-এ একটি ছবি ছাড়লে, Orova ছবিটি JSON বডির ভেতরে base64 আকারে একই endpoint URL-এ পাঠায় — multipart নয়, সুরক্ষার জন্য আলাদা কোনো ঠিকানা নেই।
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
}শুধু image/* গ্রহণ করুন, 15 MB-এর বেশি ফাইল প্রত্যাখ্যান করুন। ফাইল সংরক্ষণের পর ছবির পূর্ণ (absolute) URL ফেরত দিন: আপেক্ষিক পথ দিলে আর্টিকেল অন্য কোথাও দেখানোর সময় ভেঙে যায়। এই action শুধু Visual Editor-এর জন্য দরকার।
/ চুক্তি — মুছে ফেলা
পোস্ট মুছুন
ব্যবহারকারী Orova-র ভেতরেই (লেখা বা রিপোর্ট স্ক্রিনে) একটি প্রকাশিত আর্টিকেল সরালে, Orova আপনার ওয়েবসাইটকেও সেটি মুছতে বলে। request যায় একই endpoint URL-এ, একই Bearer token-সহ POST হিসেবে — শুধু বডি আলাদা:
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
}url দিয়ে পোস্ট খুঁজুন (না পেলে slug দিয়ে), মুছুন বা অপ্রকাশিত করুন, তারপর { "deleted": true } সহ 200 দিন — খালি 204 দিলেও চলবে। পোস্ট আর না থাকলে 404 দিন, Orova বুঝবে আগেই মুছে গেছে। { "deleted": false } দিলে বোঝায় পোস্টটি সরানো হয়নি। সাধারণ প্রকাশের request-এ কখনো action ফিল্ড থাকে না, তাই পুরোনো endpoint আগের মতোই চলে — মুছে ফেলার অংশ করা ঐচ্ছিক, তবে করা উচিত।
/ নিরাপত্তা
নিরাপত্তা নোট
- সবসময় Bearer token যাচাই করুন. আপনার endpoint একটি পাবলিক URL — যে কেউ কল করতে পারে। Authorization হেডারই একমাত্র প্রমাণ যে request সত্যিই Orova থেকে এসেছে, তাই সংরক্ষিত কী-র সাথে হুবহু না মেলা token-যুক্ত সব request প্রত্যাখ্যান করুন।
- HTTPS-এ endpoint চালান. গোপন কী হেডারে যায়। HTTPS পথে সেটি পড়া হওয়া থেকে রক্ষা করে।
- কোডে কী রাখবেন না. এটি এনভায়রনমেন্ট ভেরিয়েবল বা সিক্রেট ম্যানেজারে রাখুন, কখনও কোনো ফাইলে হার্ড-কোড করে commit করবেন না। কোনোভাবে ফাঁস হয়ে গেলে প্রজেক্ট → কানেকশন থেকে নতুন কী তৈরি করুন।
- content_html-কে কনটেন্ট হিসেবে দেখুন, বিশ্বাসযোগ্য markup হিসেবে নয়. আপনার CMS-এ অন্য যেকোনো আর্টিকেলের মূল অংশের মতোই সতর্কভাবে এটি সংরক্ষণ ও প্রদর্শন করুন।
/ শেষ কথা
চুক্তি বলতে এটুকুই
endpoint চালু হয়ে প্রজেক্টে নিবন্ধিত হলে Orova আপনার সাইটে স্বয়ংক্রিয়ভাবে প্রকাশ করবে — ঠিক WordPress ব্যবহারকারীদের মতো। প্রতিটি শেষ হওয়া আর্টিকেল আপনার সার্ভারে পৌঁছে একটি পোস্ট হয়, আর তার পাবলিক URL রিপোর্ট ও বিশ্লেষণে ফিরে আসে, যাতে আপনি এর পারফরম্যান্স ট্র্যাক করতে পারেন।
/ সাহায্য দরকার?
endpoint সংযোগ করতে আটকে গেছেন? আপনার ওয়ার্কস্পেসে সহায়তা অংশ খুলুন, অথবা আমাদের একটি বার্তা পাঠান।
