OXIRANKER DEVELOPER SƏNƏDLƏRİ

OxiRanker Sənədləri

Saytınızı OxiRanker xidmətlərinə qoşmaq üçün səliqəli sənədləşmə mərkəzi. WordPress inteqrasiyası və ya API inteqrasiyası ilə başlayın, sonra bələdçini addım-addım izləyin.

Rəsmi sənədlərTam funksiyalı V1Sayt sahibləri, developer-lər və inteqrasiya komandaları üçün
Sənədlər menyusu
Menyudan bir bələdçi seçin. Bu səhifə OxiRanker üçün əsas sənədləşmə mərkəzidir.
API xidməti

API xidməti

Xüsusi saytlar, xüsusi CMS platformaları, Next.js, Laravel, Node.js, PHP və ya Python backend-ləri üçün Export API və Webhook istifadə edin.

Domen
Təsdiqlənib
Məzmun
Hazır
API
Webhook
Vacib saxlama bildirişi

OxiRanker təyinat saytı üçün daimi hosting deyil

OxiRanker təyinat saytının məzmunu, şəkilləri və ya ixrac edilmiş faylları üçün daimi hosting zəmanəti vermir. OxiRanker istifadəçi məzmunu üçün hosting xidməti deyil və yaradılmış məzmun, cover şəkilləri, Open Graph şəkilləri və ya çıxış faylları OxiRanker infrastrukturunda 90 gündən artıq qalmaya bilər.

Buna görə, çıxışı qəbul etdikdən sonra təyinat saytı yekun məqaləni, şəkilləri, SEO məlumatlarını, Open Graph məlumatlarını və Schema məlumatlarını öz verilənlər bazasında, serverində, saxlamasında və ya CDN-də saxlamalıdır və açıq göstərim üçün OxiRanker URL-lərinə güvənməməlidir.

Təlim videosu

Bağlantı təlim videosu

WordPress-i qoşmazdan və ya API inteqrasiyasını tətbiq etməzdən əvvəl bu videodan vizual bələdçi kimi istifadə edin.

API çıxışı

Çıxış axınını addım-addım tətbiq edin

Əvvəlcə Export Token və Webhook Secret-i backend-də saxlayın, sonra Webhook receiver, verilənlər bazası, UPSERT məntiqi, Image Mirroring və gündəlik sync-i tamamlayın.

ADDIM 01

OxiRanker-də qeydiyyatdan keçin və domen yaradın

Əvvəlcə OxiRanker-də qeydiyyatdan keçin, hesabınıza daxil olun və Domains bölməsindən Add Domain düyməsinə klikləyin.

Düzgün domen formatı

Domain name sahəsinə yalnız kök domeni daxil edin. Ünvan http, https və ya www daxil etməməlidir.

example.com

Yanlış formatlar

Domen sahəsinə bu formatları daxil etməyin.

https://example.com
http://example.com
www.example.com
Domen yaradıldıqdan sonra
Domen formatı etibarlıdırsa, OxiRanker domeni yaradır və sizi domen sahibliyinin təsdiqi addımına aparır.
ADDIM 02

Domen sahibliyini təsdiqləyin

Bu addımda domenin sizə məxsus olduğunu və ya onu idarə etmək üçün girişiniz olduğunu sübut etməlisiniz.

DNS TXT

Tövsiyə olunur

Domen DNS-ə TXT record əlavə edin. Cloudflare üçün bu adətən ən sadə üsuldur.

DNS Name:
_yourdomain-verification.example.com

TXT Value:
acb1****29803

HTTP File

OxiRanker-in yoxlaya bilməsi üçün saytınızın .well-known yoluna mətn faylı yerləşdirin.

File URL:
https://example.com/.well-known/yourdomain-verification.txt

File Content:
220daaa37****42730f27

Meta Tag

Saytınızın ana səhifəsinin head bölməsinə meta tag yerləşdirin.

<meta name="yourdomain-verification" content="190208d****d275b65" />
Vacib DNS qeydi
DNS record əlavə etdikdən sonra, xüsusilə Cloudflare-də, 2-3 dəqiqə gözləməli ola bilərsiniz. Sonra eyni OxiRanker səhifəsində Confirm düyməsinə klikləyin.
Təsdiqləmə tokeninin müddəti
Domen təsdiqləmə dəyərlərinin vaxt limiti var. Hazırda təsdiqləmə dəyərləri adətən 1440 dəqiqə etibarlı olur.
ADDIM 03

İlk domeni təsdiqlədikdən sonra pulsuz tokenlər alın

İlk domeni təsdiqlədikdən sonra OxiRanker ilkin test üçün hesabınıza 1000 pulsuz token əlavə edir.

Yalnız ilk domen üçün
Bu hədiyyə yalnız ilk təsdiqlənmiş domen üçün əlavə olunur və sonrakı domenlər üçün yenidən əlavə edilmir.
ADDIM 04

Dilləri və Blog URL-ni konfiqurasiya edin

Blog URLs bölməsində saytınızın təkdilli və ya çoxdilli olduğunu və yaradılmış məqalələr üçün hansı dillərin istifadə olunacağını müəyyən edin.

Dilləri seçin

OxiRanker 24 dili dəstəkləyir. Sayt quruluşunuza əsasən bir və ya bir neçə dil seçə bilərsiniz.

Blog URL daxil edin

Hər dil üçün həmin dilə aid blog URL-ni daxil edin. Saytınız çoxdillidirsə, hər dil yolunu ayrıca daxil edin.

https://example.com/fa/blog
https://example.com/en/blog
URL strukturu
Saytınızın fərqli strukturu varsa, saytınızın real blog URL-ni daxil edin. Vacib məqam budur ki, yekun URL məqalələrin yayımlanmalı olduğu yol olmalıdır.
ADDIM 05

Hər dil üçün açar sözlər əlavə edin

Keywords tabında hər dil üçün ən azı 3 və ən çox 50 açar söz əlavə edin.

Əsas qayda

Hər dil üçün açar sözlər eyni dildə daxil edilməlidir. Məqalə dili ingiliscədirsə, açar sözlər də ingiliscə olmalıdır.

Açar sözləri necə əlavə etmək olar

Hər açar sözü yazdıqdan sonra əlavə etmək üçün Enter düyməsinə basın. Bütün açar sözləri tamamladıqdan sonra Save düyməsinə klikləyin.

Ümumi səhv
İngilis dili üçün türk dilində açar sözlər daxil etsəniz, ingilis məzmununda türk ifadələri görünə bilər. Açar söz dili məqalə dili ilə uyğun olmalıdır.
ADDIM 06

Domen Article Profile-ni tamamlayın

Article Profile OxiRanker-ə brendinizin nə olduğunu, kimlər üçün yazdığını, hansı tondan istifadə etməli olduğunu və hansı mövzulardan qaçmalı olduğunu bildirir.

Sahə

Bazar və ya biznes kateqoriyasını müəyyən edir. Misal: Dubayda daşınmaz əmlak məsləhətçiliyi və əmlak alqı-satqısı.

Biznes təsviri

Biznesin nə satdığını, kimlərə xidmət etdiyini, necə işlədiyini və onu fərqləndirən cəhətləri izah edir.

Auditoriya

Məzmunun kimə xitab etməli olduğunu müəyyən edir. Hər auditoriya ayrıca saxlanıla bilər.

Ton

Yaradılan məzmunun üslubunu və səsini idarə edir, məsələn rəsmi, tədris yönümlü, sadə, texniki və ya satış yönümlü.

Məzmun məqsədi

Məqalələrin nəyi əldə etməli olduğunu müəyyən edir, məsələn müştəri cəlb etmək, trafiki artırmaq və ya istifadəçiləri maarifləndirmək.

Qadağan olunmuş mövzular

Brendin danışmamalı olduğu və ya əlaqələndirilməməli olduğu hər şey burada daxil edilir.

İstəyə bağlı CTA

CTA oxucunun məqaləni oxuduqdan sonra etməsini istədiyiniz hərəkət deməkdir. Hansı mətnin uyğun olduğuna əmin deyilsinizsə, bu sahəni boş buraxmaq daha yaxşıdır.

Çoxdilli profil
Saytınız çoxdillidirsə, profili yalnız bir dildə tamamlamanız kifayətdir. OxiRanker eyni profil əsasında digər dillər üçün lazımi versiyaları hazırlaya bilər.
ADDIM 07

Daxili və xarici linkləmə

OxiRanker məqalələr daxilində daxili və xarici linkləri ağıllı şəkildə tətbiq edə bilər.

Daxili linklər

Bu seçim standart olaraq aktivdir və onu aktiv saxlamaq daha yaxşıdır. Daxili linkləmə axtarış motorlarına saytınızın məzmun strukturunu daha yaxşı anlamağa kömək edir.

İlk məqalədə adətən daxili linklər yaradılmır, çünki hələ əvvəlki məqalə yoxdur. İkinci məqalədən etibarən sistem daxili linkləmə edə bilər.

Xarici linklər

Xarici linklər rəsmi və etibarlı mənbələrə əlavə olunur və SEO səlahiyyətinin istəmədən ötürülməməsi üçün nofollow kimi işarələnir.

ADDIM 08

AI ilə profil keyfiyyətini yoxlayın

Article Profile tamamlandıqdan sonra OxiRanker profil keyfiyyətini yoxlayır.

85+
Saxlamaq üçün tələb olunan minimum bal
95
Təkmilləşdirmələrdən sonra adətən əldə olunan əla bal
AI
Hər sahə üçün peşəkar təkliflər
Bal 85-dən aşağıdırsa
Sistem yekun saxlamaya icazə vermir və problemli hər sahə üçün izahlar və təkmilləşdirmə təklifləri göstərir. Təklifləri tətbiq edib yenidən saxlaya bilərsiniz.
ADDIM 09

Məqalə xülasələri üçün Telegram-ı qoşun

Profili uğurla saxladıqdan sonra məqalə xülasələrinin Telegram kanalına göndərilməsini aktivləşdirə bilərsiniz.

1

Botu əlavə edin

@Oxiranker_Bot-u Telegram kanalınıza əlavə edin və onu Admin edin.

2

Kanal istifadəçi adını daxil edin

Kanal adını @ ilə daxil edin. Misal: @my_channel

3

Xülasə göndərilməsini aktivləşdirin

Etibarlı kanal qeydiyyata alındıqdan sonra məqalə xülasəsinin göndərilməsini aktivləşdirin.

Telegram faydası
Aktivdirsə, məzmun yaradıldıqdan sonra məqalə xülasəsi şəkil və linklə birlikdə Telegram kanalına göndərilir. Bu, saytınıza trafik yollarını gücləndirə bilər.
ADDIM 10

Avtomatik məqalə mühərrikini konfiqurasiya edin

Automatic article generation tabında avtomatik məqalə yaratma mühərrikini idarə edə bilərsiniz.

Ağıllı mövzu seçimi

Sistem uyğun, unikal və yayımlana bilən mövzuları seçmək üçün açar sözlərdən və Article Profile-dən istifadə edir.

Brendə uyğun yaradılma

Məqalə yaradılarkən ton, auditoriya, məzmun məqsədi və brend məhdudiyyətləri nəzərə alınır.

Planlaşdırılmış yayımlama

Aylıq tutum ay boyunca paylanır ki, məzmun yayımlanması daha təbii və ardıcıl görünsün.

Aylıq tutum

7 articles / month
10 articles / month
15 articles / month
30 articles / month

30 məqalə demək olar ki, gündə bir məqalə deməkdir. 15 məqalə təxminən gün aşırı deməkdir. 10 məqalə təxminən hər iki-üç gündən bir deməkdir. 7 məqalə təxminən hər üç-dörd gündən bir deməkdir.

Məqalə uzunluğu və şəkil

Məqalə uzunluğu Short, Standard və ya Long ola bilər. Standard əksər saytlar üçün balanslı seçimdir.

Məqalə şəkilləri aktiv və ya deaktiv edilə bilər və şəkil mövzusu Light və ya Dark seçilə bilər.

API saytları üçün qeyd
Avtomatik mühərrik məqalələri OxiRanker daxilində yaradır. Yaradıldıqdan sonra hər məqaləni xüsusi saytınıza köçürmək üçün Export API, Webhook, verilənlər bazası saxlanması və Image Mirroring tətbiq etməlisiniz.
ADDIM 11

Generate-dən ilk məqaləni yaradın

Domeni hazırladıqdan sonra Generate menyusunu açın, domeni seçin və New Content və ya New Article düyməsinə klikləyin.

1

Dil

Hər məzmun sorğusu üçün yalnız bir dil seçilir.

2

Mövzu

Aydın bir mövzu yazın. Source URL istəyə bağlıdır.

3

Şəkil

Şəkli aktiv və ya deaktiv edin və Light və ya Dark mövzusunu seçin.

4

Ödəniş və yaradılma

Xərc cüzdandan çıxılır və məqalə yaradılması başlayır.

Yaradılma müddəti
Məqalə və şəkil yaradılması adətən təxminən 2-3 dəqiqə çəkir. Tamamlandıqdan sonra məqalə OxiRanker daxilində görünür.
Source URL
Source URL daxil edilərsə, OxiRanker mövzunu daha yaxşı anlamaq üçün ondan istifadə edir, lakin kopyalanmış məzmun yaratmır. Sistem unikal məzmun yaratmaq üçün hazırlanmışdır.
ADDIM 12

Preview, SEO Report və JSON Output-u yoxlayın

Məqalə yaradıldıqdan sonra keyfiyyət yoxlanışı və yayımlama hazırlığı üçün bir neçə vacib çıxış mövcuddur.

Preview

Məqalə mətnini və yaradılmış şəkli göstərir. Bu bölmə yayımlamadan əvvəl yekun keyfiyyəti yoxlamaq üçün faydalıdır.

SEO Report

SEO Score, title, meta description, canonical, açar sözlər, schema, başlıqlar, linklər, şəkillər və OpenGraph daxil olmaqla başa düşülən SEO hesabatı göstərir.

JSON Output

Texniki istifadəçilər üçün slug, html_body, schema, şəkil URL-ləri, tag-lər, kateqoriya, oxuma müddəti və yaradılma/yenilənmə tarixləri daxil olmaqla tam məqalə çıxışını göstərir.

Çıxışların mənası
Bu çıxışlar məqalənin sadəcə düz mətn olmadığını göstərir. O, WordPress, CMS, API və yayımlama sistemləri üçün hazırlanmış strukturlaşdırılmış, SEO-ya hazır məzmundur.
ADDIM 13

Export API və Webhook dəqiq olaraq nə edir?

OxiRanker-də məqalə yaradıldıqdan sonra təyinat saytı onu Export API ilə oxuya bilər və ya məqalə hazır olduqda Webhook vasitəsilə bildiriş ala bilər.

Üsul 1: Export API

Təyinat saytı lazım olduqda Export Token ilə OxiRanker-dən məqalələri oxuya bilər. Bu üsul əl ilə sync, gündəlik sync, məqalə siyahısı səhifələri və tam məqalə JSON-unun alınması üçün istifadə olunur.

GET https://oxiranker.com/api/v1/users/domains/1/export/articles?limit=20&offset=0
Authorization: Bearer YOUR_EXPORT_TOKEN
Accept: application/json
GET https://oxiranker.com/api/v1/users/domains/1/articles/5/export/json
Authorization: Bearer YOUR_EXPORT_TOKEN
Accept: application/json

Üsul 2: Webhook

Yeni məqalə yaradıldıqda və ya məqalə yeniləndikdə OxiRanker təyinat saytının endpoint-inə bildiriş göndərir. Webhook tam məqaləni göndərmir. O, yalnız məqalə identifikatorunu göndərir ki, təyinat saytı tam məqaləni Export JSON API-dən ala bilsin.

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"
}
Çox vacib qeyd
Webhook yalnız yüngül mesajdır. Təyinat saytı Webhook daxilində tam məqalə gözləməməlidir. domain_id və article_id qəbul etdikdən sonra tam məqaləni Export JSON API-dən almalı və öz verilənlər bazasında saxlamalıdır.
ADDIM 14

Məzmun saxlanması məsuliyyəti və Image Mirroring

Təyinat saytı yekun məqaləni və şəkilləri öz infrastrukturunda saxlamalıdır.

Təyinat saytı nəyi saxlamalıdır

Təyinat saytının verilənlər bazasında tam məqalə mətni
Təyinat serverində, saxlamada və ya CDN-də əsas məqalə şəkli
Təyinat serverində, saxlamada və ya CDN-də Open Graph şəkli
SEO, OpenGraph və Article Schema məlumatları
Orijinal çıxışı qorumaq üçün raw_detail_payload və raw_list_item

Düzgün şəkil yolu nümunəsi

OxiRanker şəkil URL-lərini birbaşa və daimi istifadə etmək düzgün deyil. Şəkil endirilməli və məqalə URL-ləri təyinat saytının daxili URL-ləri ilə əvəz edilməlidir.

https://oxiranker.com/uploads/articles/3_5/cover.webp
https://example.com/uploads/site-articles/oxiranker/1/5/cover.webp
OxiRanker təyinat saytı üçün daimi hosting deyil
OxiRanker təyinat saytı üçün çıxış məzmununu və şəkilləri daimi saxlamaqdan məsul deyil. OxiRanker istifadəçi məzmunu üçün hosting xidməti deyil və yaradılmış məzmun, cover şəkilləri, Open Graph şəkilləri və ya çıxış faylları OxiRanker infrastrukturunda 90 gündən artıq qalmaya bilər. Buna görə, təyinat saytı yekun məqaləni, şəkilləri, SEO məlumatlarını, OpenGraph və Schema-nı öz verilənlər bazasında, serverində, saxlamasında və ya CDN-də saxlamalıdır.
ADDIM 15

Export Token və hazır endpoint-ləri alın

Export Token və istifadəyə hazır endpoint-lər məqalə səhifəsindən, Outputs tabından və API Output bölməsindən əldə olunur.

Export Token haradan alınır

OxiRanker-də ilk məqaləni yaradın.
Həmin məqalə səhifəsini açın.
Outputs tabını açın.
API Output bölməsini açın.
Token management-dən token yaradın.
Tam token yalnız bir dəfə göstərilir.
Tokeni təyinat saytının backend-ində və ya .env faylında saxlayın.
https://oxiranker.com/en/pannel/generate/{domainId}/articles/{articleId}

İstifadəyə hazır endpoint-lər

Eyni məqalə səhifəsində, API Output bölməsində Ready-to-use endpoints hazırlanmış URL-ləri göstərir.

https://oxiranker.com/api/v1/users/domains/1/export/articles?limit=20&offset=0
https://oxiranker.com/api/v1/users/domains/1/articles/1/export/json
https://oxiranker.com/api/v1/users/domains/1/articles/1/export/html?canonical_mode=absolute&include_css=0
Token-in rotasiyası
OxiRanker panelində Export Token rotasiya edilərsə, əvvəlki tokenin müddəti bitir. Yeni dəyər dərhal təyinat saytının .env faylında və ya backend mühitində köhnə dəyəri əvəz etməlidir və təyinat backend-i yenidən başladılmalı və ya yenidən deploy edilməlidir.
ADDIM 16

Webhook Secret və təyinat endpoint-i yaradın

Webhook Secret də məqalə səhifəsindən, Outputs tabından və API Output bölməsindən yaradılır.

Webhook Secret harada yaradılır?

Məqalə səhifəsini açın.
Outputs tabını açın.
API Output bölməsini açın.
Webhook Secret bölməsində secret yaradın.
Tam secret yalnız bir dəfə göstərilir.
Secret-i təyinat saytının .env faylında saxlayın.

Sabit təyinat endpoint-i

OxiRanker təyinat Webhook-u üçün yalnız aşağıdakı sabit yolu qəbul edir. Təyinat saytı bu endpoint-i öz backend-ində yaratmalıdır.

POST /api/oxiranker/webhook

https://example.com/api/oxiranker/webhook

Bu endpoint yalnız POST qəbul etməli, raw body-ni saxlamalı, timestamp və signature-i yoxlamalı və webhook.test üçün uğurlu cavab qaytarmalıdır.

Aktiv event-lər
Hazırkı versiyada event-lər sabitdir: article.created və article.updated. Bağlantını test etmək üçün event dəyəri webhook.test göndərilir.
ADDIM 17

Təyinat saytı üçün tələb olunan .env dəyərləri

OxiRanker təyinat saytının fayllarına və ya .env faylına girişə malik deyil. Təyinat saytının developer-i bu dəyərləri öz backend-ində saxlamalıdır.

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=50

Təhlükəsizlik dəyərləri

OXIRANKER_EXPORT_API_TOKEN
Export API token yalnız backend-də saxlanmalıdır.
OXIRANKER_WEBHOOK_SECRET
Webhook Secret yalnız backend-də saxlanmalıdır.
OXIRANKER_WEBHOOK_MAX_SKEW_MS
Webhook üçün icazə verilən maksimum zaman fərqi. 300000 5 dəqiqə deməkdir.

Saxlama dəyərləri

SITE_ARTICLE_IMAGE_UPLOAD_DIR
Təyinat serverində mirror edilmiş şəkillərin saxlanması üçün fiziki yol.
SITE_ARTICLE_IMAGE_MAX_BYTES
Şəkil endirmə və saxlama üçün icazə verilən maksimum ölçü.
PUBLIC_BASE_URL
Yekun şəkil və məqalə URL-lərini yaratmaq üçün istifadə olunan açıq təyinat sayt URL-si.
Frontend təhlükəsizliyi
Export Token və Webhook Secret frontend koduna, istifadəçiyə görünən JavaScript-ə, localStorage-a və ya window object-ə yerləşdirilməməlidir.
ADDIM 18

Export API: List, JSON, HTML və ZIP

Təyinat saytı Export API-dən istifadə edərək məqalə siyahısını və ya hər məqalənin tam çıxışını qəbul edə bilər.

Domen üçün məqalə siyahısını alın

GET https://oxiranker.com/api/v1/users/domains/:domainId/export/articles?limit=20&offset=0
Authorization: Bearer YOUR_EXPORT_TOKEN
Accept: application/json

limit məqalələrin sayını müəyyən edir və hazırda 1 ilə 50 arasında məhdudlaşdırılıb. offset səhifələmə üçün istifadə olunur. lang istəyə bağlıdır və fa, en və ya tr kimi müəyyən dil üçün məqalələri almaq üçün istifadə olunur.

Tam məqaləni JSON kimi alın

GET https://oxiranker.com/api/v1/users/domains/:domainId/articles/:articleId/export/json
Authorization: Bearer YOUR_EXPORT_TOKEN
Accept: application/json

Bu, təyinat saytı üçün ən vacib çıxışdır. Təyinat saytı tam məqalə JSON-unu öz verilənlər bazasında saxlamalı və açıq göstərim üçün öz verilənlər bazasından oxumalıdır.

Hazır HTML alın

GET https://oxiranker.com/api/v1/users/domains/1/articles/5/export/html?canonical_mode=absolute&include_css=0
Authorization: Bearer YOUR_EXPORT_TOKEN

HTML hazır çıxış istəyən saytlar üçün uyğundur, lakin daha peşəkar yanaşma JSON-u saxlayıb təyinat saytının öz şablonu ilə render etməkdir.

ZIP çıxışı alın

GET https://oxiranker.com/api/v1/users/domains/1/articles/5/export/zip
Authorization: Bearer YOUR_EXPORT_TOKEN

ZIP çıxışına article.json, meta.json, assets.json, schema.jsonld, index.html, version.txt və README.txt daxildir.

ADDIM 19

Webhook imzası və təhlükəsiz Webhook qəbulu

Təyinat saytı orijinal raw body istifadə edərək Webhook imzasını yoxlamalıdır.

Webhook header-ləri

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=...

İmza formulu

payload_to_sign = timestamp + "." + rawBody
signature = "sha256=" + HMAC_SHA256(webhook_secret, payload_to_sign)

Təyinat saytı əvvəlcə JSON-u parse edib sonra yenidən string-ə çevirərsə, sıra və ya boşluqlar dəyişə bilər və imza etibarsız ola bilər. İmza yoxlanışı üçün orijinal raw body istifadə olunmalıdır.

Timing-safe müqayisə
İmzaları expected === received ilə müqayisə etməyin. Node.js-də crypto.timingSafeEqual istifadə etmək daha yaxşıdır.
ADDIM 20

Webhook qəbul etmək üçün sadə Node.js kod nümunəsi

Bu Express nümunəsi raw body, timestamp, signature, webhook.test və article event-ləri ilə işləyir.

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,
  });
});
ADDIM 21

Təyinat saytı üçün tövsiyə olunan verilənlər bazası

Təyinat saytı məqalələri öz verilənlər bazasında saxlamalı və unique constraint ilə təkrarların qarşısını almalıdır.

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);
PostgreSQL qeydi
PostgreSQL-də fars və ya Unicode mətnləri üçün sadə dırnaqlar istifadə olunur. N'...' kimi bir şey lazım deyil və istifadə olunmamalıdır.
ADDIM 22

UPSERT ilə təkrarların qarşısını alın

Məqalə hər Webhook üçün yenidən insert edilməməlidir. Əgər artıq mövcuddursa, yenilənməlidir.

Təkrarların qarşısını almaq üçün əsas açar
Təkrarların qarşısını almaq üçün ən vacib constraint budur: UNIQUE (source_provider, source_domain_id, source_article_id)
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();
ADDIM 23

Webhook-dan sonra tam məqaləni fetch edin və sync edin

Webhook gəldikdə, təyinat saytı Export API-dən tam məqaləni fetch etməli, şəkilləri mirror etməli və məqaləni UPSERT etməlidir.

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,
  });
}
ADDIM 24

Image Mirroring və şəkil saxlanması qaydaları

Təyinat saytı şəkilləri endirməli, öz infrastrukturunda saxlamalı və məqalə URL-lərini əvəz etməlidir.

Image Mirroring qaydaları

Yalnız HTTPS URL-lər qəbul edilməlidir.
Fayl həqiqətən şəkil olmalıdır.
content-type image/ ilə başlamalıdır.
Boş fayllar saxlanmamalıdır.
Fayl ölçüsü limiti aşmamalıdır.
cover və og eynidirsə, yalnız bir dəfə endirin.
Mirror etdikdən sonra html_body və article_schema daxilində URL-ləri əvəz edin.

Tövsiyə olunan saxlama yolu

/uploads/site-articles/oxiranker/1/5/cover.webp
/uploads/site-articles/oxiranker/1/5/og.webp
https://example.com/uploads/site-articles/oxiranker/1/5/cover.webp
ADDIM 25

Etibarlılıq üçün gündəlik sync

Təkcə Webhook kifayət deyil. Təyinat saytı buraxılmış məqalələri bərpa etmək üçün gündəlik sync də etməlidir.

Gündəlik sync niyə lazımdır?

Təyinat saytı müvəqqəti olaraq işləməyə bilər.
Webhook timeout ola bilər.
Deploy və ya şəbəkə problemləri baş verə bilər.
Məqalə yaradıla bilər, amma Webhook-u buraxıla bilər.

Gündəlik sync alqoritmi

Offset-i 0-dan başlayın.
limit 20 və ya 50 istifadə edin.
Export List API-dən məqalə siyahısını fetch edin.
Hər element üçün həmin məqalənin Export JSON-unu fetch edin.
Şəkilləri mirror edin.
Məqaləni UPSERT ilə saxlayın.
Offset-i artırın və total tamamlanana qədər davam edin.
ADDIM 26

Məqalələri təyinat saytında göstərin

Məqalələr site_articles-də saxlandıqdan sonra təyinat saytı hər açıq göstərim üçün OxiRanker-ə qoşulmamalıdır. O, öz verilənlər bazasından oxumalıdır.

Blog siyahısı səhifəsi

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;

Məqalə detal səhifəsi

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;
Tövsiyə olunan məqalə URL-si
Çoxdilli saytlar üçün /{lang}/blog/{slug} nümunəsindən istifadə edə bilərsiniz. Misal: /fa/blog/smart-internal-links
ADDIM 27

SEO, Schema, RTL və HTML render

Təyinat saytı SEO məlumatlarını öz verilənlər bazasından oxumalı və məqalə səhifəsində render etməlidir.

SEO sahələri

səhifə başlığı üçün title
meta description üçün meta_description
canonical üçün effective_canonical_url
Open Graph üçün og_title və og_description
sosial preview şəkli üçün og_image_url və ya cover_image_url
JSON-LD üçün article_schema

HTML render

<div
  className="article-content"
  dangerouslySetInnerHTML={{ __html: article.html_body }}
/>

Təyinat saytının ciddi təhlükəsizlik siyasəti varsa, HTML-i saxlamazdan və ya göstərməzdən əvvəl sanitize edə bilər.

RTL və LTR

Hər məqalədə lang, dir və is_rtl sahələri var. dir rtl-dirsə, məqalə səhifəsi sağdan sola render edilməlidir.

<article dir="rtl">
  ...
</article>
ADDIM 28

Ümumi xətalar və mənaları

Təyinat saytı xətaları ingiliscə, aydın və başa düşülən olmalıdır ki, troubleshooting sürətlə aparılsın.

Export API xətaları

Domen export tokeni yoxdur.
Export API token göndərilməyib. Authorization: Bearer YOUR_EXPORT_TOKEN göndərilməlidir.
Domen export tokeni etibarsızdır.
Token yanlışdır, rotasiya edilib, bu domenlə əlaqəli deyil və ya domainId yanlışdır.
Token tələb olunan scope-a malik deyil.
Token tələb olunan scope-a malik deyil. Yeni tokenlərdə articles:read və exports:read olmalıdır.
lang etibarsızdır.
Query parameter-dəki lang dəyəri yanlış göndərilib.

Webhook xətaları

Webhook URL HTTPS istifadə etməlidir.
Webhook URL https:// ilə başlamalıdır.
Webhook imzası etibarsızdır.
Webhook Secret yanlışdır, secret rotasiya edilib, raw body dəyişib və ya imza yanlış hesablanıb.
Webhook timestamp müddəti bitib və ya etibarsızdır.
Timestamp köhnədir, gələcəkdədir və ya etibarsızdır. Server saatını və NTP-ni yoxlayın.
Webhook test göndərilməsi uğursuz oldu.
Təyinat saytı 200-dən 299-a qədər uğurlu status qaytarmadı, timeout oldu və ya webhook.test-i düzgün idarə etmədi.
ADDIM 29

Yekun API və Webhook test siyahısı

Tətbiqdən sonra bu testlər bağlantını əvvəldən sona qədər yoxlayır.

Export Token və JSON testi

GET https://oxiranker.com/api/v1/users/domains/1/export/articles?limit=2&offset=0
Authorization: Bearer YOUR_EXPORT_TOKEN
Accept: application/json
GET https://oxiranker.com/api/v1/users/domains/1/articles/5/export/json
Authorization: Bearer YOUR_EXPORT_TOKEN
Accept: application/json

Webhook testi

Təyinat Webhook-unu Postman ilə imzasız çağırırsınızsa, təhlükəsizlik xətası almalısınız. Bu, endpoint-in aktiv olduğunu və təhlükəsizliyi yoxladığını göstərir.

{
  "error": "missing_webhook_signature",
  "message": "Webhook signature header is required."
}

Sonra OxiRanker daxilində Test Webhook düyməsinə klikləyin. Receiver webhook.test-i dəstəkləyirsə, response_status 200 olmalıdır.

Rotasiyadan sonra
Webhook Secret və ya Export Token rotasiya edilərsə, yeni dəyəri dərhal kopyalayın, təyinat saytının .env faylında əvəz edin və təyinat backend-ini yenidən başladın və ya yenidən deploy edin.
ADDIM 30

Düzgün tətbiq üçün vacib qaydalar

API inteqrasiyasında sistemin təhlükəsiz, sabit və saxlanıla bilən qalması üçün bu qaydalara əməl edilməlidir.

Export Token yalnız backend-də saxlanmalıdır.
Webhook Secret yalnız backend-də saxlanmalıdır.
Təyinat Webhook endpoint-i dəqiq olaraq /api/oxiranker/webhook olmalıdır.
Webhook URL HTTPS istifadə etməlidir.
Webhook signature və timestamp həmişə yoxlanmalıdır.
Məqalələr sadə insert ilə deyil, UPSERT ilə saxlanmalıdır.
Təkrarların qarşısını almaq üçün unique constraint tələb olunur.
Şəkillər OxiRanker-dən endirilməli və təyinat saytında saxlanmalıdır.
Təyinat saytı daimi olaraq OxiRanker şəkil URL-lərindən asılı olmamalıdır.
Şəkil URL-ləri html_body və article_schema daxilində əvəz edilməlidir.
Webhook uğursuz olarsa, gündəlik sync buraxılmış məqaləni bərpa etməlidir.
İstifadəçilərə və ya log-lara göstərilən xətalar ingiliscə və başa düşülən olmalıdır.
Məqalə arxivlənibsə, avtomatik sync onu yenidən yayımlamamalıdır.
Orijinal çıxış məlumatlarının itməməsi üçün raw_detail_payload və raw_list_item qorunmalıdır.
Export Token və ya Webhook Secret rotasiya edilərsə, yeni dəyər .env-də əvəz edilməli və backend yenidən başladılmalı və ya yenidən deploy edilməlidir.
ADDIM 31

Tam API axını xülasəsi

Bu addımları tamamladıqdan sonra xüsusi saytınız OxiRanker tərəfindən yaradılmış məqalələri təhlükəsiz şəkildə qəbul edə, saxlaya, mirror edə və yayımlaya bilər.

OxiRanker-də qeydiyyatdan keçin
Domen əlavə edin
Domen sahibliyini təsdiqləyin
Dilləri seçin və Blog URL əlavə edin
Hər dil üçün açar sözlər əlavə edin
Article Profile-ni tamamlayın
Lazımdırsa Telegram-ı konfiqurasiya edin
Avtomatik məqalə mühərrikini konfiqurasiya edin
Generate-dən ilk məqaləni yaradın
Preview və SEO Report-u yoxlayın
API Output-dan Export Token alın
Hazır Export API endpoint-lərini alın
Webhook Secret alın
Təyinat backend-ində sabit /api/oxiranker/webhook endpoint-i yaradın
Token və Secret-i təyinat saytının .env faylında saxlayın
site_articles cədvəlini və unique constraint-i yaradın
Export JSON-dan tam məqalə fetch etməni tətbiq edin
Image Mirroring tətbiq edin
UPSERT tətbiq edin
Gündəlik sync tətbiq edin
Məqalə, SEO, OG və Schema-nı təyinat verilənlər bazasından render edin
Yekun Export API və Webhook testlərini icra edin