OYUN QURDU Corporate
API arayışı · v1

Oyun Qurdu Corporate API

Oyun yükləmələrini və rəqəmsal hədiyyə kartlarını topdan qiymətə alıb öz məhsulunuzda çatdırmaq üçün REST API. Sifarişlər hesabınızdakı əvvəlcədən ödənilmiş balansdan ödənilir.

Əsas ünvan
https://corporative.oyunqurdu.az/api/v1
  • Bütün sorğu və cavablar JSON, UTF-8-dir. API cavablarındakı mesajlar ingiliscədir — kodunuz onlara arxalana bilər.
  • Yalnız HTTPS. Adi HTTP yönləndirilir və API çağırışları üçün işlədilməməlidir.
  • Versiya yolun bir hissəsidir (/v1). Versiyanı dəyişmədən sahə əlavə edirik; v1 daxilində sahələri heç vaxt silmirik və adını dəyişmirik.
  • İki növ məhsul var: yükləmə (birbaşa oyun hesabına yazılır — oyunçu ID-sini göndərirsiniz) və kod (hədiyyə kartları — kodu cavabda alırsınız).

Sürətli başlanğıc

1. Daxil olun və API açarları səhifəsində açar yaradın. 2. Balansınızın sıfırdan çox olduğuna əmin olun. 3. Məhsulu tapın, canlı qiymətini yoxlayın və sifariş verin:

# 1. find the product code
curl "https://corporative.oyunqurdu.az/api/v1/products?category=pubg-mobile" \
  -H "Authorization: Bearer $OQ_API_KEY"

# 2. live price right now
curl "https://corporative.oyunqurdu.az/api/v1/products/PUBGM-660-UC/quote" \
  -H "Authorization: Bearer $OQ_API_KEY"

# 3. order it (max_unit_price locks the quoted price)
curl -X POST https://corporative.oyunqurdu.az/api/v1/orders \
  -H "Authorization: Bearer $OQ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"product": "PUBGM-660-UC", "fields": {"player_id": "5123456789"}, "reference": "INV-10045"}'

# 4. read the result (or wait for the webhook)
curl https://corporative.oyunqurdu.az/api/v1/orders/reference/INV-10045 \
  -H "Authorization: Bearer $OQ_API_KEY"

Kimlik yoxlaması

Hər sorğuya (GET /ping və GET /openapi.json istisna) API açarı lazımdır. Onu bearer token kimi göndərin:

Authorization: Bearer oqc_Ab3dE5fG7h_••••••••••••••••••••••••••••••••••••••••

X-API-Key: oqc_… başlığı da qəbul olunur.

  • Açarlar oqc_ ilə başlayır. Bir neçə açarınız ola bilər (məs. hər server üçün biri) və hər birini ayrıca ləğv edə bilərsiniz.
  • Açar yalnız bir dəfə, yaradılanda göstərilir. Biz yalnız onun izini saxlayırıq; itmiş açarı bərpa etmək olmur — yenisini yaradın.
  • Hər açarı məhdudlaşdırmaq olar: icazəli IP-lər, icazəli saytlar, gündəlik xərc həddi və ya yalnız oxuma (sifarişsiz).
  • Açarları serverinizdə saxlayın. Onları heç vaxt mobil tətbiqə, brauzer koduna və ya açıq repozitoriyaya qoymayın.

Saytdan istifadə

Veb səhifənin içindəki açarı səhifəni açan hər kəs oxuya bilər. Onu öz domeninizə bağlamaq başqa saytların brauzerdə onu işlətməsinin qarşısını alır, amma açarı köçürən adam yenə də skriptdən sorğu göndərib özünü sizin sayt kimi göstərə bilər. Ona görə:

  • Ən yaxşısı: API-ni serverinizdən (və ya kiçik proksidən) çağırın və açarı orada saxlayın. Səhifəniz serverinizlə, serveriniz bizimlə danışır.
  • Google Sites-in öz serveri yoxdur və yerləşdirilmiş kod ortaq Google domenində (*.googleusercontent.com) işləyir — domen kilidi sizin saytı başqasından ayıra bilmir. Proksi kimi Google Apps Script veb tətbiqi işlədin (aşağıdakı nümunə): açar Google serverlərində skriptin xüsusiyyətlərində qalır və brauzerə heç vaxt çatmır.
  • Brauzerdən çağırmaq məcburidirsə, saytın domenini açara əlavə edin (İcazəli saytlar), ona gündəlik xərc həddi qoyun və qiymətlər üçün ayrıca yalnız oxuma açarı düşünün. Saytları olan açar yalnız o saytlardan gələn sorğulara cavab verir; saytsız açar brauzer sorğularını ümumiyyətlə rədd edir.
Google Apps Script · Code.gs
// Extensions → Apps Script. Project Settings → Script properties → OQ_API_KEY = oqc_…
// Deploy → New deployment → Web app. Embed its URL in Google Sites.
const API = "https://corporative.oyunqurdu.az/api/v1";
const KEY = PropertiesService.getScriptProperties().getProperty("OQ_API_KEY");

function call_(method, path, body) {
  const res = UrlFetchApp.fetch(API + path, {
    method: method,
    contentType: "application/json",
    headers: { Authorization: "Bearer " + KEY },
    payload: body ? JSON.stringify(body) : undefined,
    muteHttpExceptions: true,
  });
  return JSON.parse(res.getContentText());
}

function getPrice(code) {                       // google.script.run.getPrice("PUBGM-660-UC")
  return call_("get", "/products/" + encodeURIComponent(code) + "/quote");
}

function placeOrder(code, playerId, reference) { // add your own checks here
  return call_("post", "/orders", {
    product: code, fields: { player_id: playerId }, reference: reference,
  });
}

function doGet() { return HtmlService.createHtmlOutputFromFile("Index"); }
Veb tətbiqi aça bilən hər kəs onu çağıra bilər. Skriptə öz yoxlamalarınızı əlavə edin (məsələn, yalnız müştəri ödəyəndən sonra) və açarda gündəlik xərc həddi saxlayın.

Sorğular və cavablar

  • Pul iki onluq rəqəmli sətirdir ("9.17") — heç vaxt float deyil. Valyuta hesabın valyutasıdır (USD).
  • Vaxt UTC-də ISO 8601-dir (2026-10-24T09:12:44Z).
  • ID-lərin prefiksi var: ord_ sifarişlər, txn_ balans hərəkətləri, evt_ webhook hadisələri, acc_ hesablar.
  • Siyahılar page və per_page (ən çox 100) ilə səhifələnir və data ilə pagination qaytarır.
  • Hər cavabda X-Request-Id var. Sorğu barədə bizə yazanda onu göndərin.
  • Sondakı «/» istəyə bağlıdır: /orders və /orders/ eynidir.

Səhvlər

Səhvlər standart HTTP kodları ilə gəlir və həmişə eyni formadadır. Məntiqdə error.code işlədin — mesaj dəyişə bilər.

{
  "error": {
    "code": "insufficient_balance",
    "message": "Your balance is too low for this order.",
    "retryable": false,
    "details": {
      "balance": "4.20",
      "required": "9.17",
      "shortfall": "4.97"
    },
    "doc_url": "https://corporative.oyunqurdu.az/docs/#error-insufficient_balance"
  },
  "request_id": "req_3f9a1c0b7d2e4a6b8c1d"
}

Hər səhv həm də təkrarın kömək edib-etməyəcəyini (retryable) bildirir və aşağıdakı sətrinə keçid verir (doc_url).

codeHTTPTəkrar?Nə deməkdirNə etməli
unauthorized401 xeyr API açarı göndərilməyib.`Authorization: Bearer <key>` (və ya `X-API-Key`) göndərin.
malformed_api_key401 xeyr Bu dəyər API açarı deyil (açarlar `oqc_…_…` kimidir).Açarı tam köçürün; boşluq və dırnaq olmasın.
invalid_api_key401 xeyr Belə API açarı yoxdur.Açarı yoxlayın və ya paneldə yenisini yaradın.
api_key_revoked401 xeyr Açar ləğv edilib.Paneldə yeni açar yaradın.
account_disabled403 xeyr Hesab bağlıdır.Bizimlə əlaqə saxlayın.
ip_not_allowed403 xeyr Sorğu açarın icazəli IP siyahısında olmayan ünvandan gəlib.IP-ni paneldə açara əlavə edin. `details.ip` gördüyümüz ünvandır.
origin_not_allowed403 xeyr Sorğu açarın sayt siyahısında olmayan saytdan gəlib.Domeni paneldə açara əlavə edin. `details.origin` gördüyümüzdür.
key_read_only403 xeyr Bu açar oxuya bilir, amma sifariş verə bilmir.Sifariş icazəsi olan açar işlədin və ya paneldə icazəni açın.
invalid_json400 xeyr Gövdə düzgün JSON obyekti deyil.`Content-Type: application/json` ilə JSON obyekti göndərin.
unsupported_media_type415 xeyr Gövdə JSON deyil.`Content-Type: application/json` yazın.
payload_too_large413 xeyr Sorğunun gövdəsi 32 KB-dan böyükdür.Daha kiçik gövdə göndərin.
validation_error422 xeyr Bir və ya bir neçə parametr yoxdur və ya səhvdir.`details` hər parametri `code` və `message` ilə sadalayır.
invalid_parameter422 xeyr Sorğu parametri səhvdir.`details` parametri və icazəli dəyərləri göstərir.
invalid_fields422 xeyr Məhsul sahələri (oyunçu ID, server …) yoxdur və ya səhvdir.`details.fields.<key>`-də `code` var: required, unknown_field, too_long, invalid_option, invalid_type, invalid_characters.
not_found404 xeyr Belə uc yoxdur.Yolu və `/v1` prefiksini yoxlayın.
method_not_allowed405 xeyr Bu HTTP metodu burada dəstəklənmir.`Allow` başlığına baxın.
product_not_found404 xeyr Bu kodla məhsul yoxdur.Məhsulları `GET /products` ilə siyahılayın.
product_discontinued410 xeyr Məhsul artıq satılmır.Onu kataloqunuzdan çıxarın; başqa məhsul seçin.
product_unavailable409 bəli Məhsul müvəqqəti əlçatmazdır.Sonra yenidən cəhd edin və ya başqa məhsul təklif edin.
out_of_stock409 bəli İstənilən say üçün stok çatmır.`details.available` qalan saydır. Sayı azaldın və ya sonra cəhd edin.
quantity_out_of_range422 xeyr Say məhsulun həddlərindən kənardadır.`details`-də `min` və `max` var.
not_supported422 xeyr Bu əməliyyat bu məhsul üçün yoxdur.
insufficient_balance402 xeyr Balansınız sifariş məbləğindən azdır.Balansı artırın. `details`-də `balance`, `required` və `shortfall` var.
order_limit_exceeded422 xeyr Sifarişin məbləği hesabınızın bir sifariş həddindən yuxarıdır.Sifarişi bölün və ya həddi qaldırmağımızı istəyin. `details`-də `total` və `limit` var.
key_daily_limit_exceeded422 xeyr Bu açar gündəlik xərc həddinə çatıb.00:00 UTC-ni gözləyin və ya paneldə açarın həddini qaldırın.
price_changed409 bəli Hazırkı qiymət `max_unit_price`-dan yüksəkdir.Qiyməti yenidən oxuyun (`details.unit_price`) və təkrar edin.
duplicate_reference409 xeyr Bu `reference` başqa parametrlərlə artıq işlənib.Yeni reference işlədin. `details.order_id` mövcud sifarişdir.
order_not_found404 xeyr Bu ID və ya reference ilə sifariş yoxdur.ID-ni yoxlayın.
rate_limited429 bəli Bu dəqiqədə çox sorğu.`Retry-After` saniyə gözləyin.
maintenance503 bəli Sifariş qəbulu qısa texniki iş üçün dayandırılıb.`Retry-After` saniyədən sonra təkrar edin. Balansınızdan heç nə çıxılmayıb. Baxış işləyir.
service_unavailable503 bəli Xidmətin bir hissəsi müvəqqəti əlçatmazdır.Sonra təkrar edin. Heç nə çıxılmayıb.
internal_error500 bəli Bizim tərəfdə gözlənilməz xəta.Təkrar edin. Təkrarlansa, bizə `request_id`-ni göndərin.

Sahə səhvləri

validation_error (gövdə parametrləri) və invalid_fields (məhsul sahələri) hər problemi ayrıca izah edir:

{
  "error": {
    "code": "invalid_fields",
    "message": "Some product fields are missing or invalid.",
    "retryable": false,
    "details": {"fields": {
      "server_id": {"code": "required", "message": "Server ID is required."},
      "zone":      {"code": "unknown_field", "message": "This product does not take `zone`. Expected: player_id, server_id."}
    }},
    "doc_url": "https://corporative.oyunqurdu.az/docs/#error-invalid_fields"
  },
  "request_id": "req_3f9a1c0b7d2e4a6b8c1d"
}
Pul çıxıldımı? POST /orders hər hansı səhv qaytarırsa, balansınıza toxunulmayıb. Pul yalnız sifariş yaradılanda hərəkət edir (201).
Təkrar etmək təhlükəsizdirmi? "retryable": true olan səhvlər sonra uğurlu ola bilər — fasilə ilə təkrar edin (eyni reference ilə). Qalanları üçün əvvəlcə sizin tərəfdə dəyişiklik lazımdır.

Texniki iş

Bəzən sifariş qəbulu qısa texniki iş üçün dayandırılır. Bu vaxt:

  • POST /orders Retry-After başlığı (saniyə) ilə 503 maintenance qaytarır. Heç nə çıxılmır.
  • Qalan hər şey — məhsullar, qiymətlər, balans, sifarişlər, hərəkətlər — işləməyə davam edir.
  • GET /ping və GET /account bunu service-də göstərir:
{"status": "ok", "version": "1.0.0",
 "service": {"status": "maintenance", "message": "Ordering is paused for a short maintenance…", "retry_after": 300}}

Adətən service.status operational-dır. Müştərilərinizə qısa «bir neçə dəqiqəyə yenidən cəhd edin» göstərin və Retry-After-dan sonra təkrar edin.

Sorğu limitləri

Hər hesabın dəqiqəlik sorğu limiti var (standart 120, bütün açarlar üçün ortaq). Hər cavab vəziyyəti göstərir:

X-RateLimit-Limit: 120
X-RateLimit-Remaining: 117
X-RateLimit-Reset: 41        # seconds until the window resets

Limiti aşanda Retry-After başlığı ilə 429 rate_limited alırsınız. Daha çox lazımdır? Bizə yazın.

İdempotentlik

Şəbəkə qopur. POST /orders vaxtı keçsə, sifarişin yaradılıb-yaradılmadığını bilə bilməzsiniz — ona görə həmişə öz reference-inizi göndərin (faktura və ya əməliyyat nömrəniz, hər sifariş üçün unikal):

  • Eyni reference, eyni məhsul və say → mövcud sifarişi 200 və Idempotent-Replayed: true ilə geri alırsınız. Heç nə iki dəfə çıxılmır.
  • Eyni reference, fərqli parametrlər → 409 duplicate_reference.
  • Sifarişi istənilən vaxt reference ilə tapın: GET /orders/reference/{reference}.

Hesab və balans

GET/account

Şirkətiniz, girişiniz, balansınız, sorğu limitiniz, webhook ayarlarınız və xidmətin vəziyyəti.

GET/balance
{"balance": "1250.40", "currency": "USD"}

Balansı pulu köçürdükdən sonra komandamız artırır. Hər hərəkət balans hərəkətlərində görünür.

Kateqoriyalar

GET/categories

Oyunlar və xidmətlər, hər biri üçün mövcud regionlarla.

{"data": [
  {"code": "free-fire", "name": "Free Fire", "regions": ["CIS", "EU", "ID"], "product_count": 37},
  {"code": "steam", "name": "Steam Wallet", "regions": ["CIS", "GLOBAL"], "product_count": 29}
]}

Məhsullar

GET/products

Bütün məhsullar sizin qiymətlərinizlə. Kodlara baxmaq bazara sorğu tələb etmir — dərhal cavab verir. Süzgəclər:

categoryKateqoriya kodu, məs. free-fire
regionGLOBAL, EU, TR, US, CIS, RU, ID
typetopup və ya code
qAd və kodda axtar
in_stocktrue — yalnız indi sifariş verilə bilən məhsullar
livetrue — kateqoriyanın qiymətini indi bazardan yenilə (category lazımdır)
page, per_pageSəhifələmə (per_page ≤ 100)
GET/products/{code}
{
  "code": "PUBGM-660-UC",
  "name": "PUBG Mobile — 660 UC",
  "category": "pubg-mobile",
  "category_name": "PUBG Mobile",
  "region": "GLOBAL",
  "type": "topup",
  "price": "9.17",
  "currency": "USD",
  "in_stock": true,
  "stock": null,
  "min_quantity": 1,
  "max_quantity": 10,
  "fields": [
    {
      "key": "player_id",
      "label": "Player ID",
      "type": "text",
      "required": true
    }
  ],
  "description": "Enter your Player ID before placing the order."
}
codeSabit məhsul kodu. Heç vaxt dəyişmir — onu öz sisteminizdə saxlayın.
typetopup: fields-dəki oyun hesabına yazılır. code: hədiyyə kartı kodlarını alırsınız.
priceVahid qiymətiniz, ən azı 15 dəqiqədə bir bazardan yenilənir (price_updated_at). İndiki dəqiq qiymət üçün quote ucunu işlədin.
stockKodlar üçün mövcud say. null — stokla məhdud deyil (yükləmələr).
min_quantity / max_quantityBir sifarişdə icazəli say.
fieldsSifarişdə fields-ə nə göndərməli — məs. player_id, server_id. Kodlar üçün boşdur.

Canlı qiymətlər

GET/products/{code}/quote?quantity=2

Bazardan indiki qiyməti soruşur, marjanızı əlavə edir və vahid qiymətinizi və cəmi qaytarır. Qiyməti müştərinizə göstərməzdən əvvəl işlədin.

{
  "product": "PUBGM-660-UC",
  "name": "PUBG Mobile — 660 UC",
  "quantity": 2,
  "unit_price": "9.17",
  "total": "18.34",
  "currency": "USD",
  "available": true,
  "in_stock": true,
  "stock": null,
  "live": true,
  "quoted_at": "2026-10-24T09:12:40Z",
  "valid_until": "2026-10-24T09:13:40Z",
  "hint": "Send max_unit_price with the order to lock this price."
}
  • live: true — indi qiymətləndirilib. false — bazar cavab vermədi, bu son bilinən qiymətdir.
  • Qiymət dəyişə bilər. Sifarişlə max_unit_price (quote-dakı unit_price) göndərin: arada qiymət qalxıbsa, sifariş 409 price_changed ilə rədd edilir və heç nə çıxılmır.
  • Bütöv kateqoriya üçün birdən: GET /products?category=pubg-mobile&live=true.

Oyunçu ID-sini yoxlamaq

POST/products/{code}/validate

Yükləmə məhsulları üçün: müştəridən pul almazdan əvvəl oyun hesabını yoxlayın. Hər oyun bunu dəstəkləmir — onda 422 not_supported alırsınız.

POST /products/MLBB-GLOBAL-86-DIAMONDS/validate
{"fields": {"player_id": "123456789", "server_id": "2001"}}

→ {"valid": true, "player_name": "ShadowFox"}

Sifariş yarat

POST/orders
SahəMəcburiTəsvir
productbəliMəhsul kodu.
quantityxeyrStandart 1. Məhsulun min/max həddləri daxilində olmalıdır.
fieldsyükləmələr üçünMəhsulun fields-indəki hər açarla obyekt. Naməlum açarlar rədd edilir.
referencetövsiyə olunurSizin unikal nömrəniz (1–64 simvol: hərf, rəqəm, _ . : -). Sorğunu təkrar etməyi təhlükəsiz edir.
max_unit_pricexeyrVahid qiymət indi daha yüksəkdirsə, sifarişi 409 price_changed ilə rədd et.
callback_urlxeyrBu sifarişin webhook-larını alan https ünvanı — hesabın webhook-una əlavə olaraq.

Məbləğ dərhal balansınızdan çıxılır və sifariş processing ilə başlayır:

201 Created
{
  "id": "ord_7kq2m9xw4hz8n3pd5t",
  "reference": "INV-10045",
  "status": "processing",
  "status_message": "The order is being fulfilled.",
  "product": {
    "code": "STEAM-GLOBAL-20-USD",
    "name": "Steam Wallet (Global) — 20 USD"
  },
  "quantity": 2,
  "unit_price": "21.62",
  "total": "43.24",
  "currency": "USD",
  "fields": {},
  "delivery": null,
  "failure": null,
  "created_at": "2026-10-24T09:12:44Z",
  "updated_at": "2026-10-24T09:12:47Z",
  "completed_at": null
}

Pulu çıxmazdan əvvəl canlı qiyməti, stoku və mövcudluğu yoxlayırıq. Biri tutmasa səhv alırsınız və heç nə çıxılmır.

Sifarişin həyat dövrü

statusSonNə deməkdir
processingxeyrİcra olunur. Adətən saniyələr; bəzi yükləmələr bir neçə dəqiqə çəkir.
completedbəliHazırdır. Kodlar delivery.codes-dadır; yükləmələrdə hesaba yazılıb.
failedbəliİcra oluna bilmədi. Məbləğ balansınıza qaytarıldı. failure.code-a baxın.
on_holdxeyrKomandamız əl ilə yoxlayır (nadir hal). completed və ya refunded olacaq — heç nə etmək lazım deyil.
refundedbəliKomandamız balansınıza qaytarıb.

Tamamlanmış sifariş:

{
  "id": "ord_7kq2m9xw4hz8n3pd5t",
  "reference": "INV-10045",
  "status": "completed",
  "status_message": "The order is complete.",
  "product": {
    "code": "STEAM-GLOBAL-20-USD",
    "name": "Steam Wallet (Global) — 20 USD"
  },
  "quantity": 2,
  "unit_price": "21.62",
  "total": "43.24",
  "currency": "USD",
  "fields": {},
  "delivery": {
    "type": "code",
    "codes": [
      "XXXXX-XXXXX-XXXXX",
      "YYYYY-YYYYY-YYYYY"
    ],
    "message": null
  },
  "failure": null,
  "created_at": "2026-10-24T09:12:44Z",
  "updated_at": "2026-10-24T09:12:47Z",
  "completed_at": "2026-10-24T09:12:47Z"
}

Uğursuzluq kodları

Sifariş failed ilə bitəndə failure.code səbəbi deyir. Məbləğ həmişə balansınıza qayıdır.

failure.codeNə deməkdirNə etməli
invalid_account_idOyun hesabının ID-si (və ya server) qəbul edilmədi.Sahələri düzəldin və yeni sifariş verin.
out_of_stockSifariş icra olunana qədər stok bitdi.Sonra təkrar edin.
product_unavailableİcra zamanı məhsul əlçatmaz oldu.Başqa məhsul təklif edin.
maintenanceSifariş qəbulu qısa texniki iş üçün dayandırılmışdı.Bir neçə dəqiqəyə təkrar edin.
fulfillment_failedSifariş icra oluna bilmədi.Bir dəfə təkrar edin; yenə olsa bizə yazın.
refundedSifariş komandamız tərəfindən geri qaytarıldı.

Sifarişləri almaq

GET/orders/{id}
GET/orders/reference/{reference}
GET/orders

Siyahı süzgəcləri: status, product, reference, from, to (ISO tarixlər), page, per_page. Ən yenisi birinci.

Sorğulama: processing olduqca hər 2–5 saniyədən bir yoxlayın; son vəziyyətdən sonra dayanın. Webhook-lar sizi sorğulamadan qurtarır.

Balans hərəkətləri

GET/transactions

Hər balans hərəkəti, ən yenisi birinci, sonrakı balansla. Növlər: deposit, purchase, refund, adjustment, withdrawal. Süzgəclər: type, from, to.

{"data": [
  {"id": "txn_k2m8q4w7x3z9n5p6r1", "type": "purchase", "amount": "-9.17",
   "balance_after": "1241.23", "currency": "USD", "order_id": "ord_7kq2m9xw4hz8n3pd5t",
   "description": "PUBGM-660-UC × 1", "created_at": "2026-10-24T09:12:44Z"}
], "pagination": {"page": 1, "per_page": 50, "total": 1, "total_pages": 1}}

Webhook-lar

Webhook ünvanını paneldəki Webhook-lar səhifəsində (və ya hər sifariş üçün callback_url ilə) yazın. Sifarişin vəziyyəti dəyişəndə order.updated hadisəsini POST edirik:

POST https://your-server.example/oq/webhook
Content-Type: application/json
X-OQ-Event: order.updated
X-OQ-Delivery: evt_9w3k7m2q8x4z6n5p1r
X-OQ-Signature: t=1792833167,v1=5f1c…e9a2

{
  "id": "evt_9w3k7m2q8x4z6n5p1r",
  "type": "order.updated",
  "created_at": "2026-10-24T09:12:47Z",
  "data": {
    "order": {
      "id": "ord_7kq2m9xw4hz8n3pd5t",
      "reference": "INV-10045",
      "status": "completed",
      "status_message": "The order is complete.",
      "product": {
        "code": "STEAM-GLOBAL-20-USD",
        "name": "Steam Wallet (Global) — 20 USD"
      },
      "quantity": 2,
      "unit_price": "21.62",
      "total": "43.24",
      "currency": "USD",
      "fields": {},
      "delivery": {
        "type": "code",
        "codes": [
          "XXXXX-XXXXX-XXXXX",
          "YYYYY-YYYYY-YYYYY"
        ],
        "message": null
      },
      "failure": null,
      "created_at": "2026-10-24T09:12:44Z",
      "updated_at": "2026-10-24T09:12:47Z",
      "completed_at": "2026-10-24T09:12:47Z"
    }
  }
}
  • 10 saniyə ərzində istənilən 2xx ilə cavab verin. Əks halda 1 dəq, 5 dəq, 30 dəq, 2 saat və 6 saatdan sonra təkrar göndəririk.
  • Hadisələr bir neçə dəfə və qarışıq sırada gələ bilər. data.order.status və updated_at işlədin, sizdə artıq bitmiş sifarişlərin hadisələrini nəzərə almayın.
  • X-OQ-Delivery ID-si hər hadisə üçün unikaldır — təkrarları atmaq üçün işlədin.

İmzanı yoxlamaq

Hər webhook imza açarınızla imzalanır (whsec_…, Webhook-lar səhifəsində). X-OQ-Signature belədir: t=<unix time>,v1=<hex>, burada hex = HMAC-SHA256(secret, "<t>.<raw request body>"). İmza uyğun gəlmirsə və ya t 5 dəqiqədən köhnədirsə sorğunu rədd edin.

import hashlib, hmac, time

def verify(raw_body: bytes, header: str, secret: str) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    t, sig = parts.get("t", ""), parts.get("v1", "")
    if not t.isdigit() or abs(time.time() - int(t)) > 300:
        return False
    expected = hmac.new(secret.encode(), f"{t}.".encode() + raw_body,
                        hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, sig)
Xam gövdəni işlədin. Baytları olduğu kimi yoxlayın — JSON-u oxuyub yenidən yazmaq onları dəyişir və imza uyğun gəlmir.

Tövsiyələr

  • Həmişə reference göndərin. Vaxt keçəndə eyni reference ilə təkrar edin və ya sifarişi onunla tapın.
  • Ödənişdən dərhal əvvəl qiyməti /quote ilə alın və onu max_unit_price kimi göndərin.
  • GET /products-u hər sifarişdən əvvəl çağırmaq əvəzinə bir neçə dəqiqəlik yadda saxlayın.
  • Mümkün olan yerdə oyunçu ID-lərini /validate ilə yoxlayın və fields açarlarını dəqiq köçürün.
  • 503-ü müvəqqəti sayın — sonra təkrar edin; heç nə çıxılmayıb.
  • İstehsal açarları üçün hər server üçün ayrıca açar, IP siyahısı və gündəlik hədd işlədin.
  • POST /orders üçün ən azı 30 saniyəlik gözləmə vaxtı saxlayın.

OpenAPI

Postman, Insomnia və ya kod generatorları üçün tam maşın oxunaqlı spesifikasiya (OpenAPI 3.1). İnteraktiv versiya API arayışı səhifəsindədir.

Spesifikasiya Aç
https://corporative.oyunqurdu.az/api/v1/openapi.json

Dəyişikliklər

v1.0.0İlk buraxılış: məhsullar, canlı qiymətlər, sifarişlər, balans, hərəkətlər, webhook-lar, oyunçu ID yoxlaması, strukturlu səhvlər, texniki iş vəziyyəti, açar məhdudiyyətləri (IP-lər, saytlar, gündəlik hədd, yalnız oxuma).