OYUN QURDU Corporate
API referansı · v1

Oyun Qurdu Corporate API

Oyun yüklemelerini ve dijital hediye kartlarını toptan fiyatla alıp kendi ürününüzde teslim etmek için bir REST API. Siparişler hesabınızdaki ön ödemeli bakiyeden ödenir.

Temel URL
https://corporative.oyunqurdu.az/api/v1
  • Tüm istek ve yanıtlar JSON, UTF-8'dir. API yanıtlarındaki mesajlar İngilizcedir, kodunuz bunlara güvenebilir.
  • Yalnızca HTTPS. Düz HTTP yönlendirilir ve API çağrıları için kullanılmamalıdır.
  • Sürüm yolun bir parçasıdır (/v1). Sürümü değiştirmeden alan ekleriz; v1 içinde alanları asla kaldırmaz veya yeniden adlandırmayız.
  • İki tür ürün vardır: yükleme (doğrudan oyun hesabına yüklenir — oyuncu ID'sini gönderirsiniz) ve kod (hediye kartları — kodu yanıtta alırsınız).

Hızlı başlangıç

1. Giriş yapın ve API anahtarları sayfasında bir anahtar oluşturun. 2. Bakiyenizin sıfırın üzerinde olduğundan emin olun. 3. Bir ürün bulun, canlı fiyatını kontrol edin ve sipariş 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 doğrulama

Her isteğin (GET /ping ve GET /openapi.json hariç) bir API anahtarına ihtiyacı vardır. Bearer token olarak gönderin:

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

X-API-Key: oqc_… başlığı da kabul edilir.

  • Anahtarlar oqc_ ile başlar. Birden fazla anahtarınız olabilir (örn. her sunucu için bir tane) ve her birini ayrı ayrı iptal edebilirsiniz.
  • Anahtar yalnızca bir kez, oluşturulduğunda gösterilir. Yalnızca parmak izini saklarız; kaybolan anahtar geri getirilemez — yenisini oluşturun.
  • Her anahtar sınırlandırılabilir: izinli IP adresleri, izinli siteler, günlük harcama sınırı veya salt okunur (sipariş yok).
  • Anahtarları sunucunuzda tutun. Asla bir mobil uygulamaya, tarayıcı koduna veya herkese açık bir depoya koymayın.

Bir web sitesinden kullanım

Bir web sayfasının içindeki anahtarı sayfayı açan herkes okuyabilir. Onu alan adınıza kısıtlamak diğer sitelerin tarayıcıda kullanmasını engeller, ancak anahtarı kopyalayan biri yine de bir betikten istek gönderip sizin siteniz gibi davranabilir. Bu yüzden:

  • En iyisi: API'yi sunucunuzdan (veya küçük bir proxy'den) çağırın ve anahtarı orada tutun. Sayfanız sunucunuzla, sunucunuz bizimle konuşur.
  • Google Sites'ın kendi sunucusu yoktur ve gömülü kod ortak bir Google alan adında (*.googleusercontent.com) çalışır — alan adı kilidi sizin sitenizi diğerlerinden ayıramaz. Proxy olarak bir Google Apps Script web uygulaması kullanın (aşağıdaki örnek): anahtar, Google sunucularında betiğin özelliklerinde kalır ve tarayıcıya asla ulaşmaz.
  • Tarayıcıdan çağırmanız şartsa, sitenin alan adını anahtara ekleyin (İzinli siteler), ona bir günlük harcama sınırı verin ve fiyatlar için ayrı bir salt okunur anahtar düşünün. Siteleri olan bir anahtar yalnızca o sitelerden gelen isteklere yanıt verir; sitesi olmayan bir anahtar tarayıcı isteklerini tamamen reddeder.
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"); }
Web uygulamasını açabilen herkes onu çağırabilir. Betiğe kendi kontrollerinizi ekleyin (örneğin yalnızca müşteriniz ödeme yaptıktan sonra) ve anahtarda günlük harcama sınırı tutun.

İstekler ve yanıtlar

  • Para, iki ondalıklı bir dizedir ("9.17") — asla float değildir. Para birimi hesabın para birimidir (USD).
  • Zamanlar UTC'de ISO 8601'dir (2026-10-24T09:12:44Z).
  • ID'lerin önekleri vardır: ord_ siparişler, txn_ işlemler, evt_ webhook olayları, acc_ hesaplar.
  • Listeler page ve per_page (en fazla 100) ile sayfalanır ve data ile pagination döndürür.
  • Her yanıtta X-Request-Id bulunur. Bir istek hakkında bize yazarken bunu ekleyin.
  • Sondaki eğik çizgi isteğe bağlıdır: /orders ve /orders/ aynıdır.

Hatalar

Hatalar standart HTTP durum kodları kullanır ve her zaman aynı biçimdedir. Mantığınızda error.code kullanın — mesaj değişebilir.

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

Her hata ayrıca tekrar denemenin işe yarayıp yaramayacağını (retryable) söyler ve aşağıdaki satırına bağlantı verir (doc_url).

codeHTTPTekrar?AnlamıNe yapmalı
unauthorized401 hayır API anahtarı gönderilmedi.`Authorization: Bearer <key>` (veya `X-API-Key`) gönderin.
malformed_api_key401 hayır Bu değer bir API anahtarı değil (anahtarlar `oqc_…_…` biçimindedir).Anahtarın tamamını kopyalayın; boşluk veya tırnak olmasın.
invalid_api_key401 hayır Böyle bir API anahtarı yok.Anahtarı kontrol edin veya panelden yenisini oluşturun.
api_key_revoked401 hayır Anahtar iptal edildi.Panelden yeni bir anahtar oluşturun.
account_disabled403 hayır Hesap devre dışı.Bizimle iletişime geçin.
ip_not_allowed403 hayır İstek, anahtarın izin listesinde olmayan bir IP'den geldi.IP'yi panelden anahtara ekleyin. `details.ip` gördüğümüz adrestir.
origin_not_allowed403 hayır İstek, anahtarın site listesinde olmayan bir siteden geldi.Alan adını panelden anahtara ekleyin. `details.origin` gördüğümüzdür.
key_read_only403 hayır Bu anahtar okuyabilir ama sipariş veremez.Sipariş izni olan bir anahtar kullanın veya panelden izni açın.
invalid_json400 hayır Gövde geçerli bir JSON nesnesi değil.`Content-Type: application/json` ile bir JSON nesnesi gönderin.
unsupported_media_type415 hayır Gövde JSON değil.`Content-Type: application/json` ayarlayın.
payload_too_large413 hayır İstek gövdesi 32 KB'tan büyük.Daha küçük bir gövde gönderin.
validation_error422 hayır Bir veya birkaç parametre eksik ya da hatalı.`details` her parametreyi `code` ve `message` ile listeler.
invalid_parameter422 hayır Bir sorgu parametresi hatalı.`details` parametreyi ve izin verilen değerleri gösterir.
invalid_fields422 hayır Ürün alanları (oyuncu ID, sunucu …) eksik veya hatalı.`details.fields.<key>` içinde `code` vardır: required, unknown_field, too_long, invalid_option, invalid_type, invalid_characters.
not_found404 hayır Böyle bir uç nokta yok.Yolu ve `/v1` önekini kontrol edin.
method_not_allowed405 hayır Bu HTTP metodu burada desteklenmiyor.`Allow` başlığına bakın.
product_not_found404 hayır Bu kodla bir ürün yok.Ürünleri `GET /products` ile listeleyin.
product_discontinued410 hayır Ürün artık satılmıyor.Kataloğunuzdan çıkarın; başka bir ürün seçin.
product_unavailable409 evet Ürün geçici olarak kullanılamıyor.Daha sonra tekrar deneyin veya başka bir ürün sunun.
out_of_stock409 evet İstenen miktar için yeterli stok yok.`details.available` kalan miktardır. Miktarı azaltın veya sonra deneyin.
quantity_out_of_range422 hayır Miktar ürünün sınırlarının dışında.`details` içinde `min` ve `max` vardır.
not_supported422 hayır Bu işlem bu ürün için kullanılamaz.
insufficient_balance402 hayır Bakiyeniz sipariş tutarından az.Bakiye yükleyin. `details` içinde `balance`, `required` ve `shortfall` vardır.
order_limit_exceeded422 hayır Sipariş tutarı hesabınızın sipariş başına sınırının üzerinde.Siparişi bölün veya sınırı yükseltmemizi isteyin. `details` içinde `total` ve `limit` vardır.
key_daily_limit_exceeded422 hayır Bu anahtar günlük harcama sınırına ulaştı.00:00 UTC'yi bekleyin veya panelden anahtarın sınırını yükseltin.
price_changed409 evet Güncel fiyat `max_unit_price` değerinden yüksek.Fiyatı yeniden okuyun (`details.unit_price`) ve tekrar deneyin.
duplicate_reference409 hayır Bu `reference` farklı parametrelerle zaten kullanıldı.Yeni bir reference kullanın. `details.order_id` mevcut siparişdir.
order_not_found404 hayır Bu ID veya reference ile bir sipariş yok.ID'yi kontrol edin.
rate_limited429 evet Bu dakikada çok fazla istek.`Retry-After` saniye bekleyin.
maintenance503 evet Sipariş alımı kısa bir bakım için durduruldu.`Retry-After` saniye sonra tekrar deneyin. Bakiyenizden bir şey düşülmedi. Görüntüleme çalışır.
service_unavailable503 evet Hizmetin bir bölümü geçici olarak kullanılamıyor.Daha sonra tekrar deneyin. Hiçbir şey düşülmedi.
internal_error500 evet Bizim tarafımızda beklenmeyen bir hata.Tekrar deneyin. Tekrarlanırsa bize `request_id` gönderin.

Alan hataları

validation_error (gövde parametreleri) ve invalid_fields (ürün alanları) her sorunu ayrı ayrı açıklar:

{
  "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"
}
Ücret alındı mı? POST /orders herhangi bir hata döndürürse bakiyenize dokunulmamıştır. Para yalnızca sipariş oluşturulduğunda hareket eder (201).
Tekrar denemek güvenli mi? "retryable": true olan hatalar daha sonra başarılı olabilir — beklemeli olarak tekrar deneyin (aynı reference ile). Diğerleri önce sizin tarafınızda bir değişiklik gerektirir.

Bakım

Zaman zaman sipariş alımı kısa bir bakım için durdurulur. Bu süre zarfında:

  • POST /orders, Retry-After başlığıyla (saniye) 503 maintenance döndürür. Hiçbir ücret alınmaz.
  • Diğer her şey — ürünler, fiyatlar, bakiye, siparişler, işlemler — çalışmaya devam eder.
  • GET /ping ve GET /account bunu service içinde gösterir:
{"status": "ok", "version": "1.0.0",
 "service": {"status": "maintenance", "message": "Ordering is paused for a short maintenance…", "retry_after": 300}}

Normalde service.status operational olur. Müşterilerinize kısa bir «birkaç dakika sonra tekrar deneyin» gösterin ve Retry-After sonrasında tekrar deneyin.

İstek limitleri

Her hesabın dakikalık bir istek limiti vardır (varsayılan 120, tüm anahtarlar arasında ortak). Her yanıt nerede olduğunuzu gösterir:

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

Limiti aşarsanız Retry-After başlığıyla 429 rate_limited alırsınız. Daha fazlası mı lazım? Bize yazın.

İdempotentlik

Ağlar çöker. Bir POST /orders zaman aşımına uğrarsa siparişin oluşturulup oluşturulmadığını bilemezsiniz — bu yüzden her zaman kendi reference değerinizi gönderin (fatura veya işlem numaranız, sipariş başına benzersiz):

  • Aynı reference, aynı ürün ve miktar → mevcut siparişi 200 ve Idempotent-Replayed: true ile geri alırsınız. Hiçbir şey iki kez ücretlendirilmez.
  • Aynı reference, farklı parametreler → 409 duplicate_reference.
  • Siparişi istediğiniz zaman reference ile bulun: GET /orders/reference/{reference}.

Hesap ve bakiye

GET/account

Şirketiniz, girişiniz, bakiyeniz, istek limitiniz, webhook ayarlarınız ve hizmet durumu.

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

Bakiye, para transferinizden sonra ekibimiz tarafından yüklenir. Her hareket işlemler altında listelenir.

Kategoriler

GET/categories

Oyunlar ve hizmetler, her biri için mevcut bölgelerle.

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

Ürünler

GET/products

Tüm ürünler sizin fiyatlarınızla. Kodlara bakmak piyasaya istek gerektirmez — anında yanıt verir. Filtreler:

categoryKategori kodu, örn. free-fire
regionGLOBAL, EU, TR, US, CIS, RU, ID
typetopup veya code
qAd ve kodda ara
in_stocktrue — yalnızca şu an sipariş verilebilen ürünler
livetrue — kategorinin fiyatını şimdi piyasadan yenile (category gerekir)
page, per_pageSayfalama (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 ürün kodu. Asla değişmez — sisteminizde saklayın.
typetopup: fields içindeki oyun hesabına yüklenir. code: hediye kartı kodlarını alırsınız.
priceBirim fiyatınız, en az 15 dakikada bir piyasadan yenilenir (price_updated_at). Tam şu anki fiyat için quote uç noktasını kullanın.
stockKodlar için mevcut adet. null stokla sınırlı olmadığı anlamına gelir (yüklemeler).
min_quantity / max_quantitySipariş başına izin verilen miktar.
fieldsSiparişte fields içine ne göndermeniz gerektiği — örn. player_id, server_id. Kodlar için boştur.

Canlı fiyatlar

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

Piyasaya fiyatı tam şu an sorar, marjınızı ekler ve birim fiyatınızı ve toplamı döndürür. Fiyatı müşterinize göstermeden hemen önce kullanın.

{
  "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 — şu an fiyatlandı. false — piyasa yanıt vermedi, bu bilinen son fiyattır.
  • Fiyatlar değişebilir. Siparişle birlikte max_unit_price (teklif edilen unit_price) gönderin: arada fiyat yükseldiyse sipariş 409 price_changed ile reddedilir ve hiçbir ücret alınmaz.
  • Bütün bir kategori için tek seferde: GET /products?category=pubg-mobile&live=true.

Oyuncu ID'sini doğrulama

POST/products/{code}/validate

Yükleme ürünleri için: müşterinizden ücret almadan önce oyun hesabını kontrol edin. Her oyun desteklemez — o zaman 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"}

Sipariş oluştur

POST/orders
AlanZorunluAçıklama
productevetÜrün kodu.
quantityhayırVarsayılan 1. Ürünün min/max değerleri içinde olmalıdır.
fieldsyüklemeler içinÜrünün fields içindeki her anahtarı içeren nesne. Bilinmeyen anahtarlar reddedilir.
referenceönerilirBenzersiz kimliğiniz (1–64 karakter: harf, rakam, _ . : -). İsteği tekrar denemeyi güvenli kılar.
max_unit_pricehayırBirim fiyat artık daha yüksekse siparişi 409 price_changed ile reddet.
callback_urlhayırHesap webhook'unuza ek olarak bu siparişin webhook'larını alan https adresi.

Toplam hemen bakiyenizden düşülür ve sipariş processing olarak başlar:

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
}

Ücret almadan önce canlı fiyatı, stoku ve kullanılabilirliği kontrol ederiz. Herhangi biri başarısız olursa bir hata alırsınız ve hiçbir ücret alınmaz.

Sipariş yaşam döngüsü

statusSonAnlamı
processinghayırİşleniyor. Genellikle saniyeler; bazı yüklemeler birkaç dakika sürer.
completedevetTamam. Kodlar delivery.codes içindedir; yüklemelerde hesaba yüklendi.
failedevetTamamlanamadı. Tutar bakiyenize iade edildi. failure.code değerine bakın.
on_holdhayırEkibimiz tarafından manuel incelemede (nadir). completed veya refunded durumuna geçecek — işlem yapmanıza gerek yok.
refundedevetEkibimiz tarafından bakiyenize iade edildi.

Tamamlanmış bir sipariş:

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

Başarısızlık kodları

Bir sipariş failed ile bittiğinde failure.code nedenini söyler. Tutar her zaman bakiyenize geri döner.

failure.codeAnlamıNe yapmalı
invalid_account_idOyun hesabı ID'si (veya sunucu) kabul edilmedi.Alanları düzeltin ve yeni bir sipariş verin.
out_of_stockSipariş tamamlanmadan stok tükendi.Daha sonra tekrar deneyin.
product_unavailableİşlem sırasında ürün kullanılamaz hale geldi.Başka bir ürün sunun.
maintenanceSipariş alımı kısa bir bakım için durdurulmuştu.Birkaç dakika sonra tekrar deneyin.
fulfillment_failedSipariş tamamlanamadı.Bir kez tekrar deneyin; yine olursa bize yazın.
refundedSipariş ekibimiz tarafından iade edildi.

Siparişleri getirme

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

Liste filtreleri: status, product, reference, from, to (ISO tarihler), page, per_page. En yenisi önce.

Yoklama: processing iken her 2–5 saniyede bir kontrol edin; son durumdan sonra durun. Webhook'lar sizi yoklamadan kurtarır.

İşlemler

GET/transactions

Her bakiye hareketi, en yenisi önce, sonraki bakiyeyle birlikte. Türler: deposit, purchase, refund, adjustment, withdrawal. Filtreler: 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 URL'sini paneldeki Webhook'lar sayfasında (veya sipariş başına callback_url ile) ayarlayın. Bir siparişin durumu değiştiğinde bir order.updated olayını POST ederiz:

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 saniye içinde herhangi bir 2xx ile yanıt verin. Aksi halde 1 dk, 5 dk, 30 dk, 2 sa ve 6 sa sonra tekrar deneriz.
  • Olaylar birden fazla kez ve sırasız gelebilir. data.order.status ve updated_at kullanın, sisteminizde zaten sonlanmış siparişlerin olaylarını yok sayın.
  • X-OQ-Delivery ID'si her olay için benzersizdir — tekrarları atmak için kullanın.

İmzaları doğrulama

Her webhook imza anahtarınızla imzalanır (whsec_…, Webhook'lar sayfasında). X-OQ-Signature şöyledir: t=<unix time>,v1=<hex>, burada hex = HMAC-SHA256(secret, "<t>.<raw request body>"). İmza eşleşmiyorsa veya t 5 dakikadan eskiyse isteği reddedin.

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)
Ham gövdeyi kullanın. Baytları tam alındığı gibi doğrulayın — JSON'u ayrıştırıp yeniden yazmak onları değiştirir ve imza eşleşmez.

En iyi uygulamalar

  • Her zaman bir reference gönderin. Zaman aşımında aynı reference ile tekrar deneyin veya siparişi onunla bulun.
  • Ödemeden hemen önce fiyatı /quote ile alın ve max_unit_price olarak gönderin.
  • GET /products çağrısını her siparişten önce yapmak yerine birkaç dakika önbellekte tutun.
  • Desteklenen yerlerde oyuncu ID'lerini /validate ile doğrulayın ve fields anahtarlarını aynen kopyalayın.
  • 503 değerini geçici sayın — daha sonra tekrar deneyin; hiçbir ücret alınmadı.
  • Üretim anahtarları için her sunucuya ayrı bir anahtar, IP izin listesi ve günlük sınır kullanın.
  • POST /orders için en az 30 saniyelik bir zaman aşımı tutun.

OpenAPI

Postman, Insomnia veya kod üreteçleri için makine tarafından okunabilir tam şartname (OpenAPI 3.1). Etkileşimli sürümü API referansı sayfasındadır.

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

Değişiklik günlüğü

v1.0.0İlk sürüm: ürünler, canlı fiyatlar, siparişler, bakiye, işlemler, webhook'lar, oyuncu ID doğrulaması, yapılandırılmış hatalar, bakım durumu, anahtar kısıtlamaları (IP'ler, siteler, günlük sınır, salt okunur).