OxiRanker دستاویزات
اپنی ویب سائٹ کو OxiRanker سروسز سے جوڑنے کے لیے ایک صاف دستاویزاتی مرکز۔ WordPress انضمام یا API انضمام سے شروع کریں، پھر گائیڈ کو قدم بہ قدم فالو کریں۔
API سروس
Custom websites، custom CMS platforms، Next.js، Laravel، Node.js، PHP یا Python backend کے لیے Export API اور Webhook استعمال کریں۔
OxiRanker destination website کے لیے permanent hosting نہیں ہے
OxiRanker destination website کے content، images یا exported files کے لیے permanent hosting کی guarantee فراہم نہیں کرتا۔ OxiRanker user-content hosting service نہیں ہے، اور generated content، cover images، Open Graph images یا output files OxiRanker infrastructure پر 90 دن سے زیادہ باقی نہ رہیں۔
اس لیے output حاصل کرنے کے بعد destination website کو final article، images، SEO data، Open Graph data اور Schema data اپنی database، server، storage یا CDN میں store کرنا چاہیے، اور public display کے لیے OxiRanker URLs پر depend نہیں کرنا چاہیے۔
Connection training video
WordPress جوڑنے یا API integration implement کرنے سے پہلے اس video کو visual walkthrough کے طور پر استعمال کریں۔
Output flow کو قدم بہ قدم implement کریں
پہلے Export Token اور Webhook Secret کو اپنے backend میں store کریں، پھر Webhook receiver، database، UPSERT logic، Image Mirroring اور daily sync مکمل کریں۔
OxiRanker میں register کریں اور domain بنائیں
سب سے پہلے OxiRanker میں register کریں، اپنے account میں sign in کریں اور Domains section سے Add Domain پر کلک کریں۔
Domain کا درست format
Domain name field میں صرف root domain درج کریں۔ Address میں http، https یا www شامل نہیں ہونا چاہیے۔
example.comغلط formats
Domain field میں یہ formats درج نہ کریں۔
https://example.com
http://example.com
www.example.comDomain ownership verify کریں
اس step میں آپ کو ثابت کرنا ہوگا کہ domain آپ کا ہے یا آپ کے پاس اسے manage کرنے کی access ہے۔
DNS TXT
تجویز کردہDomain DNS میں TXT record شامل کریں۔ Cloudflare کے لیے یہ عام طور پر سب سے آسان method ہے۔
DNS Name:
_yourdomain-verification.example.com
TXT Value:
acb1****29803HTTP File
اپنی website کے .well-known path میں text file رکھیں تاکہ OxiRanker اسے verify کر سکے۔
File URL:
https://example.com/.well-known/yourdomain-verification.txt
File Content:
220daaa37****42730f27Meta Tag
اپنی website homepage کے head section میں meta tag رکھیں۔
<meta name="yourdomain-verification" content="190208d****d275b65" />پہلا domain verify ہونے کے بعد مفت token حاصل کریں
پہلا domain verify کرنے کے بعد OxiRanker initial testing کے لیے آپ کے account میں 1000 free tokens شامل کرتا ہے۔
زبانیں اور Blog URL configure کریں
Blog URLs section میں define کریں کہ آپ کی website single-language ہے یا multilingual، اور generated articles کے لیے کون سی languages استعمال ہونی چاہئیں۔
زبانیں منتخب کریں
OxiRanker 24 languages کو support کرتا ہے۔ آپ اپنی website structure کے مطابق ایک یا کئی languages منتخب کر سکتے ہیں۔
Blog URL درج کریں
ہر language کے لیے اس language کا blog URL درج کریں۔ اگر آپ کی website multilingual ہے تو ہر language path الگ درج کریں۔
https://example.com/fa/blog
https://example.com/en/blogہر language کے لیے keywords شامل کریں
Keywords tab میں ہر language کے لیے کم از کم 3 اور زیادہ سے زیادہ 50 keywords شامل کریں۔
بنیادی rule
ہر language کے keywords اسی language میں درج ہونے چاہئیں۔ اگر article language English ہے تو keywords بھی English ہونے چاہئیں۔
Keywords کیسے شامل کریں
ہر keyword لکھنے کے بعد اسے شامل کرنے کے لیے Enter دبائیں۔ تمام keywords مکمل کرنے کے بعد Save پر کلک کریں۔
Domain Article Profile مکمل کریں
Article Profile OxiRanker کو بتاتا ہے کہ آپ کا brand کیا ہے، کس کے لیے لکھتا ہے، کون سا tone استعمال کرنا چاہیے اور کن topics سے بچنا چاہیے۔
Industry
Market یا business category define کرتا ہے۔ مثال: Dubai میں real estate consulting اور property buying and selling۔
Business description
یہ explain کرتا ہے کہ business کیا sell کرتا ہے، کس کو serve کرتا ہے، کیسے کام کرتا ہے اور کیا اسے مختلف بناتا ہے۔
Audience
یہ define کرتا ہے کہ content کس سے بات کرے۔ ہر audience کو الگ save کیا جا سکتا ہے۔
Tone
Generated content کے style اور voice کو control کرتا ہے، جیسے formal، educational، simple، technical یا sales-oriented۔
Content goal
یہ define کرتا ہے کہ articles کو کیا achieve کرنا چاہیے، جیسے customers attract کرنا، traffic بڑھانا یا users کو educate کرنا۔
منع شدہ topics
وہ سب کچھ جس کے بارے میں brand کو بات نہیں کرنی چاہیے یا جس سے associate نہیں ہونا چاہیے، یہاں درج کیا جاتا ہے۔
Optional CTA
CTA اس action کو کہتے ہیں جو آپ چاہتے ہیں کہ reader article پڑھنے کے بعد کرے۔ اگر آپ کو یقین نہیں کہ کون سا text suitable ہے، تو بہتر ہے یہ field empty چھوڑ دیں۔
Internal اور external links
OxiRanker articles کے اندر internal links اور external links کو intelligent طریقے سے apply کر سکتا ہے۔
Internal links
یہ option default طور پر enabled ہوتا ہے اور اسے enabled رکھنا بہتر ہے۔ Internal linking search engines کو آپ کی website کے content structure کو بہتر سمجھنے میں مدد دیتی ہے۔
پہلے article میں internal links عام طور پر نہیں بنائے جاتے کیونکہ ابھی previous article موجود نہیں ہوتا۔ دوسرے article سے system internal linking perform کر سکتا ہے۔
External links
External links official اور trusted sources پر add کیے جاتے ہیں اور nofollow کے طور پر marked ہوتے ہیں تاکہ SEO authority غیر ارادی طور پر منتقل نہ ہو۔
AI سے profile quality check کریں
Article Profile مکمل کرنے کے بعد OxiRanker profile quality review کرتا ہے۔
Article summaries کے لیے Telegram connect کریں
Profile کامیابی سے save ہونے کے بعد آپ Telegram channel پر article summaries بھیجنا enable کر سکتے ہیں۔
Bot شامل کریں
@Oxiranker_Bot کو اپنے Telegram channel میں شامل کریں اور اسے Admin بنائیں۔
Channel username درج کریں
Channel name کو @ کے ساتھ درج کریں۔ مثال: @my_channel
Summary delivery enable کریں
Valid channel register کرنے کے بعد article summary delivery enable کریں۔
Automatic article engine configure کریں
Automatic article generation tab میں آپ automatic article generation engine کو manage کر سکتے ہیں۔
Smart topic selection
System suitable، unique اور publishable topics منتخب کرنے کے لیے keywords اور Article Profile استعمال کرتا ہے۔
Brand-aware generation
Article generation کے دوران tone، audience، content goal اور brand restrictions کو respect کیا جاتا ہے۔
Scheduled publishing
Monthly capacity کو پورے مہینے میں distribute کیا جاتا ہے تاکہ content publishing زیادہ natural اور consistent نظر آئے۔
Monthly capacity
7 articles / month
10 articles / month
15 articles / month
30 articles / month30 articles کا مطلب تقریباً روزانہ ایک article ہے۔ 15 articles کا مطلب تقریباً ایک دن چھوڑ کر ہے۔ 10 articles کا مطلب تقریباً ہر دو سے تین دن میں ہے۔ 7 articles کا مطلب تقریباً ہر تین سے چار دن میں ہے۔
Article length اور image
Article length Short، Standard یا Long ہو سکتی ہے۔ Standard زیادہ تر websites کے لیے balanced choice ہے۔
Article images enabled یا disabled ہو سکتی ہیں، اور image theme Light یا Dark ہو سکتا ہے۔
Generate سے پہلا article بنائیں
Domain تیار کرنے کے بعد Generate menu کھولیں، domain منتخب کریں اور New Content یا New Article پر کلک کریں۔
Language
ہر content request کے لیے صرف ایک language منتخب ہوتی ہے۔
Topic
واضح topic لکھیں۔ Source URL optional ہے۔
Image
Image enable یا disable کریں اور Light یا Dark theme منتخب کریں۔
Payment اور generation
Cost wallet سے deducted ہوتی ہے اور article generation شروع ہو جاتا ہے۔
Preview، SEO Report اور JSON Output review کریں
Article generated ہونے کے بعد quality review اور publishing preparation کے لیے کئی important outputs دستیاب ہوتے ہیں۔
Preview
Article text اور generated image دکھاتا ہے۔ یہ section publishing سے پہلے final quality review کرنے کے لیے مفید ہے۔
SEO Report
ایک understandable SEO report دکھاتا ہے جس میں SEO Score، title، meta description، canonical، keywords، schema، headings، links، images اور OpenGraph شامل ہیں۔
JSON Output
Technical users کے لیے full article output دکھاتا ہے، جس میں slug، html_body، schema، image URLs، tags، category، reading time اور created/updated timestamps شامل ہیں۔
Export API اور Webhook اصل میں کیا کرتے ہیں؟
OxiRanker میں article generated ہونے کے بعد destination website اسے Export API سے read کر سکتی ہے یا article ready ہونے پر Webhook کے ذریعے notified ہو سکتی ہے۔
Method 1: Export API
Destination website ضرورت کے وقت Export Token کے ذریعے OxiRanker سے articles read کر سکتی ہے۔ یہ method manual sync، daily sync، article list pages اور full article JSON fetching کے لیے استعمال ہوتی ہے۔
GET https://oxiranker.com/api/v1/users/domains/1/export/articles?limit=20&offset=0
Authorization: Bearer YOUR_EXPORT_TOKEN
Accept: application/jsonGET https://oxiranker.com/api/v1/users/domains/1/articles/5/export/json
Authorization: Bearer YOUR_EXPORT_TOKEN
Accept: application/jsonMethod 2: Webhook
جب new article created ہو یا article updated ہو، OxiRanker destination website endpoint کو notify کرتا ہے۔ Webhook full article نہیں بھیجتا۔ یہ صرف article identifier بھیجتا ہے تاکہ destination website Export JSON API سے full article fetch کر سکے۔
https://example.com/api/oxiranker/webhook{
"event": "article.created",
"domain_id": "1",
"article_id": "5",
"request_id": "5",
"lang": "fa",
"slug": "smart-internal-links",
"occurred_at": "2026-05-20T19:35:33.000Z"
}Content storage responsibility اور Image Mirroring
Destination website کو final article اور images اپنی infrastructure میں store کرنے چاہئیں۔
Destination website کو کیا store کرنا چاہیے
درست image path کی مثال
OxiRanker image URLs کو directly اور permanently استعمال کرنا درست نہیں ہے۔ Image download ہونی چاہیے اور article URLs کو destination website internal URLs سے replace کیا جانا چاہیے۔
https://oxiranker.com/uploads/articles/3_5/cover.webphttps://example.com/uploads/site-articles/oxiranker/1/5/cover.webpExport Token اور ready endpoints حاصل کریں
Export Token اور ready-to-use endpoints article page، Outputs tab اور API Output section سے دستیاب ہیں۔
Export Token کہاں سے حاصل کریں
https://oxiranker.com/en/pannel/generate/{domainId}/articles/{articleId}Ready-to-use endpoints
اسی article page میں، API Output section کے اندر، Ready-to-use endpoints prepared URLs دکھاتا ہے۔
https://oxiranker.com/api/v1/users/domains/1/export/articles?limit=20&offset=0https://oxiranker.com/api/v1/users/domains/1/articles/1/export/jsonhttps://oxiranker.com/api/v1/users/domains/1/articles/1/export/html?canonical_mode=absolute&include_css=0Webhook Secret اور destination endpoint بنائیں
Webhook Secret بھی article page، Outputs tab اور API Output section سے بنایا جاتا ہے۔
Webhook Secret کہاں بنایا جاتا ہے؟
Fixed destination endpoint
OxiRanker destination Webhook کے لیے صرف درج ذیل fixed path قبول کرتا ہے۔ Destination website کو یہ endpoint اپنے backend میں create کرنا چاہیے۔
POST /api/oxiranker/webhook
https://example.com/api/oxiranker/webhookیہ endpoint صرف POST accept کرے، raw body preserve کرے، timestamp اور signature verify کرے، اور webhook.test کے لیے successful response return کرے۔
Destination website کے required .env values
OxiRanker کو destination website files یا .env تک access نہیں ہے۔ Destination website developer کو یہ values اپنے backend میں store کرنی چاہئیں۔
OXIRANKER_EXPORT_API_BASE_URL=https://oxiranker.com
OXIRANKER_EXPORT_API_TOKEN=YOUR_EXPORT_TOKEN
OXIRANKER_WEBHOOK_SECRET=YOUR_WEBHOOK_SECRET
OXIRANKER_WEBHOOK_MAX_SKEW_MS=300000
OXIRANKER_SOURCE_PROVIDER=oxiranker
OXIRANKER_SOURCE_DOMAIN_IDS=1
SITE_ARTICLE_IMAGE_UPLOAD_DIR=/var/www/example.com/uploads/site-articles
SITE_ARTICLE_IMAGE_MAX_BYTES=10485760
PUBLIC_BASE_URL=https://example.com
OXIRANKER_SYNC_ENABLED=true
OXIRANKER_SYNC_HOUR=3
OXIRANKER_SYNC_MINUTE=10
OXIRANKER_SYNC_PAGE_LIMIT=20
OXIRANKER_SYNC_MAX_PAGES=50Security values
Storage values
Export API: List، JSON، HTML اور ZIP
Destination website Export API استعمال کر کے article list یا ہر article کا full output receive کر سکتی ہے۔
Domain کے لیے list of articles حاصل کریں
GET https://oxiranker.com/api/v1/users/domains/:domainId/export/articles?limit=20&offset=0
Authorization: Bearer YOUR_EXPORT_TOKEN
Accept: application/jsonlimit number of articles define کرتا ہے اور فی الحال 1 سے 50 کے درمیان limited ہے۔ offset pagination کے لیے استعمال ہوتا ہے۔ lang optional ہے اور specific language کے articles جیسے fa، en یا tr fetch کرنے کے لیے استعمال ہوتا ہے۔
Full article کو JSON کے طور پر حاصل کریں
GET https://oxiranker.com/api/v1/users/domains/:domainId/articles/:articleId/export/json
Authorization: Bearer YOUR_EXPORT_TOKEN
Accept: application/jsonیہ destination website کے لیے سب سے important output ہے۔ Destination website کو full article JSON اپنی database میں store کرنا چاہیے اور public display کے لیے اپنی database سے read کرنا چاہیے۔
Ready HTML حاصل کریں
GET https://oxiranker.com/api/v1/users/domains/1/articles/5/export/html?canonical_mode=absolute&include_css=0
Authorization: Bearer YOUR_EXPORT_TOKENHTML ان websites کے لیے suitable ہے جو ready output چاہتی ہیں، لیکن زیادہ professional approach یہ ہے کہ JSON store کیا جائے اور destination website کے اپنے template سے render کیا جائے۔
ZIP output حاصل کریں
GET https://oxiranker.com/api/v1/users/domains/1/articles/5/export/zip
Authorization: Bearer YOUR_EXPORT_TOKENZIP output میں article.json، meta.json، assets.json، schema.jsonld، index.html، version.txt اور README.txt شامل ہیں۔
Webhook Signature اور secure Webhook receiving
Destination website کو original raw body استعمال کرتے ہوئے Webhook signature verify کرنا چاہیے۔
Webhook headers
content-type: application/json
user-agent: Oxiranker-Webhooks/1.0
x-oxiranker-event: article.created
x-oxiranker-domain-id: 1
x-oxiranker-timestamp: 2026-05-20T19:35:33.000Z
x-oxiranker-signature: sha256=...Signature formula
payload_to_sign = timestamp + "." + rawBody
signature = "sha256=" + HMAC_SHA256(webhook_secret, payload_to_sign)اگر destination website پہلے JSON parse کرے اور پھر دوبارہ stringify کرے تو order یا spacing تبدیل ہو سکتی ہے اور signature invalid ہو سکتی ہے۔ Signature verification کے لیے original raw body استعمال ہونا چاہیے۔
Webhook receiving کے لیے simple Node.js code sample
یہ Express sample raw body، timestamp، signature، webhook.test اور article events handle کرتا ہے۔
import express from "express";
import crypto from "crypto";
const app = express();
app.use(
express.json({
verify: (req, _res, buf) => {
(req as any).rawBody = Buffer.from(buf);
},
})
);
function getHeader(req: express.Request, name: string): string {
const value = req.headers[name.toLowerCase()];
if (Array.isArray(value)) return String(value[0] || "").trim();
return String(value || "").trim();
}
function getRawBody(req: express.Request): string {
const raw = (req as any).rawBody;
if (Buffer.isBuffer(raw)) return raw.toString("utf8");
return JSON.stringify(req.body || {});
}
function createSignature(secret: string, timestamp: string, rawBody: string): string {
const payload = `${timestamp}.${rawBody}`;
const digest = crypto
.createHmac("sha256", secret)
.update(payload, "utf8")
.digest("hex");
return `sha256=${digest}`;
}
function timingSafeEqualText(a: string, b: string): boolean {
const ab = Buffer.from(a, "utf8");
const bb = Buffer.from(b, "utf8");
if (ab.length !== bb.length) return false;
return crypto.timingSafeEqual(ab, bb);
}
function isTimestampValid(timestamp: string): boolean {
const maxSkewMs = Number(process.env.OXIRANKER_WEBHOOK_MAX_SKEW_MS || 300000);
const date = new Date(timestamp);
if (Number.isNaN(date.getTime())) return false;
const diff = Math.abs(Date.now() - date.getTime());
return diff <= maxSkewMs;
}
app.post("/api/oxiranker/webhook", async (req, res) => {
const secret = String(process.env.OXIRANKER_WEBHOOK_SECRET || "").trim();
if (!secret) {
return res.status(500).json({
error: "webhook_secret_missing",
message: "Webhook secret is not configured.",
});
}
const eventHeader = getHeader(req, "x-oxiranker-event");
const domainIdHeader = getHeader(req, "x-oxiranker-domain-id");
const timestamp = getHeader(req, "x-oxiranker-timestamp");
const receivedSignature = getHeader(req, "x-oxiranker-signature");
const rawBody = getRawBody(req);
if (!eventHeader) {
return res.status(400).json({
error: "missing_webhook_event",
message: "Webhook event header is required.",
});
}
if (!domainIdHeader) {
return res.status(400).json({
error: "missing_webhook_domain_id",
message: "Webhook domain id header is required.",
});
}
if (!timestamp) {
return res.status(400).json({
error: "missing_webhook_timestamp",
message: "Webhook timestamp header is required.",
});
}
if (!receivedSignature) {
return res.status(400).json({
error: "missing_webhook_signature",
message: "Webhook signature header is required.",
});
}
if (!isTimestampValid(timestamp)) {
return res.status(401).json({
error: "invalid_webhook_timestamp",
message: "Webhook timestamp is expired or invalid.",
});
}
const expectedSignature = createSignature(secret, timestamp, rawBody);
if (!timingSafeEqualText(expectedSignature, receivedSignature)) {
return res.status(401).json({
error: "invalid_webhook_signature",
message: "Invalid webhook signature.",
});
}
const payload = req.body || {};
const event = String(payload.event || eventHeader || "").trim();
if (event === "webhook.test") {
const sourceDomainId = Number(payload.domain_id || domainIdHeader);
return res.status(200).json({
ok: true,
message: "Webhook test received successfully.",
event,
source_domain_id:
Number.isFinite(sourceDomainId) && sourceDomainId > 0 ? sourceDomainId : null,
test: true,
});
}
if (event !== "article.created" && event !== "article.updated") {
return res.status(400).json({
error: "unsupported_webhook_event",
message: "Webhook event is not supported.",
});
}
const sourceDomainId = Number(payload.domain_id || domainIdHeader);
const sourceArticleId = Number(payload.article_id);
if (!Number.isFinite(sourceDomainId) || sourceDomainId <= 0) {
return res.status(400).json({
error: "invalid_domain_id",
message: "Webhook domain id is invalid.",
});
}
if (!Number.isFinite(sourceArticleId) || sourceArticleId <= 0) {
return res.status(400).json({
error: "invalid_article_id",
message: "Webhook article id is invalid.",
});
}
// Fetch the full article from Export API and store it in the database here.
// await syncArticleFromOxiranker(sourceDomainId, sourceArticleId);
return res.status(200).json({
ok: true,
message: "Webhook processed successfully.",
event,
source_domain_id: sourceDomainId,
source_article_id: sourceArticleId,
});
});Recommended destination website database
Destination website کو articles اپنی database میں store کرنے چاہئیں اور unique constraint کے ذریعے duplicates prevent کرنے چاہئیں۔
CREATE TABLE public.site_articles (
id BIGSERIAL PRIMARY KEY,
source_provider VARCHAR NOT NULL DEFAULT 'oxiranker',
source_domain_id BIGINT NOT NULL,
source_article_id BIGINT NOT NULL,
source_request_id BIGINT NULL,
lang VARCHAR NOT NULL,
lang_label VARCHAR NULL,
dir VARCHAR NOT NULL,
is_rtl BOOLEAN NULL,
length VARCHAR NULL,
topic_text TEXT NULL,
slug VARCHAR NOT NULL,
canonical_path VARCHAR NULL,
effective_canonical_url TEXT NULL,
title TEXT NOT NULL,
meta_description TEXT NULL,
html_body TEXT NULL,
focus_keywords JSONB NOT NULL DEFAULT '[]'::jsonb,
category VARCHAR NULL,
tags JSONB NOT NULL DEFAULT '[]'::jsonb,
reading_time_minutes INTEGER NULL,
og_title TEXT NULL,
og_description TEXT NULL,
cover_image_url TEXT NULL,
og_image_url TEXT NULL,
article_schema JSONB NOT NULL DEFAULT '{}'::jsonb,
raw_list_item JSONB NOT NULL DEFAULT '{}'::jsonb,
raw_detail_payload JSONB NOT NULL DEFAULT '{}'::jsonb,
source_created_at TIMESTAMPTZ NULL,
source_updated_at TIMESTAMPTZ NULL,
sync_status VARCHAR NOT NULL DEFAULT 'synced',
last_synced_at TIMESTAMPTZ NOT NULL DEFAULT now(),
last_sync_error TEXT NULL,
publish_status VARCHAR NOT NULL DEFAULT 'draft',
published_at TIMESTAMPTZ NULL,
deleted_at TIMESTAMPTZ NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
source_cover_image_url TEXT NULL,
source_og_image_url TEXT NULL,
image_mirror_status VARCHAR NOT NULL DEFAULT 'pending',
image_mirror_error TEXT NULL,
image_mirrored_at TIMESTAMPTZ NULL,
CONSTRAINT site_articles_dir_check
CHECK (dir IN ('ltr', 'rtl')),
CONSTRAINT site_articles_reading_time_check
CHECK (reading_time_minutes IS NULL OR reading_time_minutes >= 0),
CONSTRAINT site_articles_sync_status_check
CHECK (sync_status IN ('pending', 'syncing', 'synced', 'failed')),
CONSTRAINT site_articles_publish_status_check
CHECK (publish_status IN ('draft', 'published', 'archived')),
CONSTRAINT site_articles_image_mirror_status_check
CHECK (image_mirror_status IN ('pending', 'not_needed', 'mirrored', 'failed')),
CONSTRAINT site_articles_source_unique
UNIQUE (source_provider, source_domain_id, source_article_id)
);CREATE INDEX site_articles_source_lookup_idx
ON public.site_articles (source_provider, source_domain_id, source_article_id);
CREATE INDEX site_articles_source_updated_at_idx
ON public.site_articles (source_updated_at DESC);
CREATE INDEX site_articles_slug_idx
ON public.site_articles (slug)
WHERE deleted_at IS NULL;
CREATE UNIQUE INDEX site_articles_lang_slug_active_unique
ON public.site_articles (lang, slug)
WHERE deleted_at IS NULL;
CREATE INDEX site_articles_lang_publish_idx
ON public.site_articles (lang, publish_status)
WHERE deleted_at IS NULL;
CREATE INDEX site_articles_published_at_idx
ON public.site_articles (published_at DESC)
WHERE deleted_at IS NULL;
CREATE INDEX site_articles_focus_keywords_gin_idx
ON public.site_articles USING gin (focus_keywords);
CREATE INDEX site_articles_tags_gin_idx
ON public.site_articles USING gin (tags);
CREATE INDEX site_articles_article_schema_gin_idx
ON public.site_articles USING gin (article_schema);UPSERT سے duplicates prevent کریں
Article ہر Webhook کے لیے دوبارہ inserted نہیں ہونا چاہیے۔ اگر یہ پہلے سے exists ہے تو اسے updated ہونا چاہیے۔
INSERT INTO public.site_articles (
source_provider,
source_domain_id,
source_article_id,
source_request_id,
lang,
dir,
slug,
title,
meta_description,
html_body,
focus_keywords,
category,
tags,
reading_time_minutes,
cover_image_url,
og_image_url,
article_schema,
source_created_at,
source_updated_at,
sync_status,
last_synced_at,
publish_status,
published_at,
created_at,
updated_at
)
VALUES (
'oxiranker',
1,
5,
5,
'fa',
'rtl',
'smart-internal-links',
'Article title',
'Meta description',
'<p>HTML body</p>',
'[]'::jsonb,
'SEO',
'[]'::jsonb,
7,
'https://example.com/uploads/site-articles/oxiranker/1/5/cover.webp',
'https://example.com/uploads/site-articles/oxiranker/1/5/cover.webp',
'{}'::jsonb,
'2026-05-20T19:33:23.618Z',
'2026-05-20T19:34:09.629Z',
'synced',
now(),
'published',
now(),
now(),
now()
)
ON CONFLICT (source_provider, source_domain_id, source_article_id)
DO UPDATE SET
source_request_id = EXCLUDED.source_request_id,
lang = EXCLUDED.lang,
dir = EXCLUDED.dir,
slug = EXCLUDED.slug,
title = EXCLUDED.title,
meta_description = EXCLUDED.meta_description,
html_body = EXCLUDED.html_body,
focus_keywords = EXCLUDED.focus_keywords,
category = EXCLUDED.category,
tags = EXCLUDED.tags,
reading_time_minutes = EXCLUDED.reading_time_minutes,
cover_image_url = EXCLUDED.cover_image_url,
og_image_url = EXCLUDED.og_image_url,
article_schema = EXCLUDED.article_schema,
source_created_at = EXCLUDED.source_created_at,
source_updated_at = EXCLUDED.source_updated_at,
sync_status = 'synced',
last_synced_at = now(),
last_sync_error = NULL,
publish_status = CASE
WHEN public.site_articles.publish_status = 'archived'
THEN public.site_articles.publish_status
ELSE 'published'
END,
published_at = COALESCE(public.site_articles.published_at, EXCLUDED.published_at, now()),
deleted_at = NULL,
updated_at = now();Webhook کے بعد full article fetch اور sync کریں
جب Webhook آئے تو destination website کو Export API سے full article fetch کرنا چاہیے، images mirror کرنی چاہئیں اور article UPSERT کرنا چاہیے۔
async function fetchOxirankerArticleDetail(args: {
baseUrl: string;
token: string;
domainId: number;
articleId: number;
}) {
const url = `${args.baseUrl.replace(/\/+$/, "")}/api/v1/users/domains/${args.domainId}/articles/${args.articleId}/export/json`;
const response = await fetch(url, {
method: "GET",
headers: {
Authorization: `Bearer ${args.token}`,
Accept: "application/json",
"User-Agent": "My-Site-Oxiranker-Sync/1.0",
},
});
const bodyText = await response.text();
if (response.status < 200 || response.status > 299) {
throw new Error(
`Export API request failed with HTTP status ${response.status}. Response: ${bodyText.slice(0, 1000)}`
);
}
try {
return JSON.parse(bodyText);
} catch {
throw new Error("Export API returned invalid JSON.");
}
}async function syncArticleFromWebhook(payload: any) {
const sourceDomainId = Number(payload.domain_id);
const sourceArticleId = Number(payload.article_id);
if (!Number.isFinite(sourceDomainId) || sourceDomainId <= 0) {
throw new Error("Webhook domain id is invalid.");
}
if (!Number.isFinite(sourceArticleId) || sourceArticleId <= 0) {
throw new Error("Webhook article id is invalid.");
}
const article = await fetchOxirankerArticleDetail({
baseUrl: process.env.OXIRANKER_EXPORT_API_BASE_URL!,
token: process.env.OXIRANKER_EXPORT_API_TOKEN!,
domainId: sourceDomainId,
articleId: sourceArticleId,
});
const mirroredImages = await mirrorArticleImages(article);
const finalHtmlBody = replaceImageUrls(article.html_body, mirroredImages);
const finalArticleSchema = replaceImageUrlsInJson(article.article_schema, mirroredImages);
await upsertSiteArticle({
source_provider: process.env.OXIRANKER_SOURCE_PROVIDER || "oxiranker",
source_domain_id: sourceDomainId,
source_article_id: sourceArticleId,
source_request_id: article.request_id,
lang: article.lang,
dir: article.dir,
slug: article.slug,
title: article.title,
meta_description: article.meta_description,
html_body: finalHtmlBody,
focus_keywords: article.focus_keywords,
category: article.category,
tags: article.tags,
reading_time_minutes: article.reading_time_minutes,
cover_image_url: mirroredImages.cover_image_url,
og_image_url: mirroredImages.og_image_url,
article_schema: finalArticleSchema,
raw_detail_payload: article,
source_created_at: article.created_at,
source_updated_at: article.updated_at,
});
}Image Mirroring اور image storage rules
Destination website کو images download کرنی چاہئیں، اپنی infrastructure میں store کرنی چاہئیں اور article URLs replace کرنے چاہئیں۔
Image Mirroring rules
Recommended storage path
/uploads/site-articles/oxiranker/1/5/cover.webp
/uploads/site-articles/oxiranker/1/5/og.webphttps://example.com/uploads/site-articles/oxiranker/1/5/cover.webpReliability کے لیے daily sync
Webhook alone کافی نہیں ہے۔ Destination website کے پاس missed articles recover کرنے کے لیے daily sync بھی ہونا چاہیے۔
Daily sync کیوں ضروری ہے؟
Daily sync algorithm
Destination website پر articles دکھائیں
Articles کو site_articles میں storing کرنے کے بعد destination website کو ہر public display کے لیے OxiRanker سے connect نہیں ہونا چاہیے۔ اسے اپنی database سے read کرنا چاہیے۔
Blog list page
SELECT
id,
lang,
lang_label,
dir,
is_rtl,
slug,
title,
meta_description,
category,
tags,
reading_time_minutes,
cover_image_url,
og_image_url,
source_created_at,
published_at,
created_at
FROM public.site_articles
WHERE source_provider = 'oxiranker'
AND deleted_at IS NULL
AND sync_status = 'synced'
AND publish_status = 'published'
ORDER BY COALESCE(source_created_at, published_at, created_at) DESC, id DESC
LIMIT 20 OFFSET 0;Article detail page
SELECT *
FROM public.site_articles
WHERE source_provider = 'oxiranker'
AND lang = 'fa'
AND slug = 'smart-internal-links'
AND deleted_at IS NULL
AND sync_status = 'synced'
AND publish_status = 'published'
LIMIT 1;SEO، Schema، RTL اور HTML rendering
Destination website کو SEO data اپنی database سے read کر کے article page پر render کرنا چاہیے۔
SEO fields
HTML rendering
<div
className="article-content"
dangerouslySetInnerHTML={{ __html: article.html_body }}
/>اگر destination website کی strict security policy ہو تو وہ HTML کو saving سے پہلے یا displaying سے پہلے sanitize کر سکتی ہے۔
RTL اور LTR
ہر article میں lang، dir اور is_rtl fields ہوتے ہیں۔ اگر dir rtl ہو تو article page کو right-to-left rendered ہونا چاہیے۔
<article dir="rtl">
...
</article>Common errors اور ان کا مطلب
Destination website errors English، clear اور understandable ہونے چاہئیں تاکہ troubleshooting تیزی سے ہو سکے۔
Export API errors
Webhook errors
Final API اور Webhook testing checklist
Implementation کے بعد یہ tests connection کو beginning سے end تک verify کرتے ہیں۔
Export Token اور JSON test
GET https://oxiranker.com/api/v1/users/domains/1/export/articles?limit=2&offset=0
Authorization: Bearer YOUR_EXPORT_TOKEN
Accept: application/jsonGET https://oxiranker.com/api/v1/users/domains/1/articles/5/export/json
Authorization: Bearer YOUR_EXPORT_TOKEN
Accept: application/jsonWebhook test
اگر آپ destination Webhook کو Postman سے signature کے بغیر call کریں تو آپ کو security error receive ہونا چاہیے۔ اس کا مطلب ہے endpoint active ہے اور security checks کرتا ہے۔
{
"error": "missing_webhook_signature",
"message": "Webhook signature header is required."
}پھر OxiRanker کے اندر Test Webhook پر کلک کریں۔ اگر receiver webhook.test support کرتا ہے تو response_status 200 ہونا چاہیے۔
Correct implementation کے لیے important rules
API integration میں یہ rules follow ہونے چاہئیں تاکہ system secure، stable اور maintainable رہے۔
Complete API flow summary
یہ steps مکمل کرنے کے بعد آپ کی custom website OxiRanker میں generated articles کو securely receive، store، mirror اور publish کر سکتی ہے۔