# Oyuneks Bayi API v1 > Oyuneks bayilerinin e-pin ve top-up satışını kendi sistemlerine bağladığı JSON API. Katalog ve bayi fiyatı okuma, oyuncu hesabı doğrulama, sipariş verme, teslim edilen kodu alma, bakiye/cari hareket okuma ve imzalı webhook aboneliği. Taban adres: https://oyuneks.com/bayi-api/v1 Kimlik: Authorization: Bearer (oyxb_live_ canlı, oyxb_test_ test modu; aynı adres). Başarı zarfı: {"data": ..., "mode": "live|test", "requestId": "..."} Hata zarfı: {"error":{"code","message","retryable","requestId","details"}} — dallanmayı code ile yap. Para METİN ve 2 ondalıklı ("411.50"), para birimi TRY. Tarihler ISO-8601 (+03:00). Sayfalama imleçli: yanıttaki nextCursor değerini ?cursor= ile geri gönder. POST /orders ucunda Idempotency-Key başlığı ZORUNLU; aynı anahtarla tekrar aynı siparişi döndürür. Ürün kimliği, alan adı ve fiyat UYDURULMAZ: katalog uçlarından okunur. ## Belgeler - İnsan dokümantasyonu: https://oyuneks.com/bayi-api/docs - OpenAPI 3.1: https://oyuneks.com/bayi-api/openapi.json - Postman koleksiyonu: https://oyuneks.com/bayi-api/postman.json - Anahtar üretme (giriş gerekir): https://oyuneks.com/bayi-paneli/api ## Yetki kapsamları - catalog:read: Katalog ve fiyat okuma - orders:read: Siparisleri ve kodlari okuma - orders:write: Siparis verme ve iptal (bakiyeden para duser) - balance:read: Bakiye ve cari hareket okuma - webhooks:manage: Webhook aboneligi yonetimi ## MCP sunucusu (yapay zeka istemcileri) Adres: https://oyuneks.com/bayi-api/mcp (JSON-RPC 2.0, oturumsuz, Streamable HTTP). Kimlik: AYNI bayi anahtari (Authorization: Bearer) ya da OAuth 2.1 + PKCE. Kesif: /.well-known/oauth-protected-resource/bayi-api/mcp ve /.well-known/oauth-authorization-server/bayi-api Claude Code: claude mcp add --transport http oyuneks-bayi https://oyuneks.com/bayi-api/mcp --header "Authorization: Bearer " Mod jetondan gelir; her arac yaniti "mode" alani tasir. Teslim edilen kodlar varsayilan olarak MASKELIDIR. Para harcayan araclar IKI ADIMLIDIR: onayJetonu olmadan cagri islem YAPMAZ, ozet + 5 dakikalik jeton doner. - bayi_bilgim [(herhangi) + balance:read] -> GET /bayi-api/v1/me: Bayi kimliği, firma, kademe, kullanılabilir bakiye, günlük limit ve anahtarın modu (canlı/test). - katalog_ara [catalog:read] -> GET /bayi-api/v1/catalog/products: Ürün arar: productId, bayi fiyatı, stok, zorunlu alan şeması ve adet sınırları. Sipariş öncesi zorunlu keşif adımı. - fiyat_degisiklikleri [catalog:read] -> GET /bayi-api/v1/catalog/prices: Verilen tarihten bu yana fiyatı, stoğu ya da satış durumu değişen ürünler (fiyat senkronu). - hesap_dogrula [orders:write] -> POST /bayi-api/v1/orders/validate: Top-up ürününde oyuncu hesabını tedarikçiye sorar, hesap adını döner. - siparis_ver [orders:write] -> POST /bayi-api/v1/orders (iki adimli onay): Sipariş verir. İKİ ADIMLI: önce ürün/adet/fiyat/bakiye özeti + onay jetonu, onaydan sonra sipariş. - siparislerim [orders:read] -> GET /bayi-api/v1/orders: Siparişleri listeler (durum, kaynak, tarih süzgeci). Kodlar bu listede her zaman maskelidir. - siparis_detayi [orders:read] -> GET /bayi-api/v1/orders/{siparisNo}: Tek siparişin detayı; sipariş numarası ya da kendi referansınızla. Kod isteğe bağlı olarak açık gösterilir. - siparis_iptal [orders:write] -> POST /bayi-api/v1/orders/{siparisNo}/cancel (iki adimli onay): Bekleyen kalemleri iptal eder ve tutarı bakiyeye iade eder. İKİ ADIMLI onay ister. - ekstre [balance:read] -> GET /bayi-api/v1/reports/statement: Dönem ekstresi: açılış/kapanış bakiyesi, yükleme, sipariş, iade toplamları ve hareket satırları. - webhook_ayarim [webhooks:manage] -> GET /bayi-api/v1/webhooks: Webhook aboneliğini gösterir (adres, olaylar, durum). Adres değiştirme panelden yapılır. - webhook_test [webhooks:manage] -> POST /bayi-api/v1/webhooks/test: Kayıtlı webhook adresine imzalı bir ping olayı gönderir ve sonucu döner. ## Uçlar ### Hesap & bakiye - GET /bayi-api/v1/me [(herhangi)] — Anahtar sağlık kontrolü. Bayi kimliği, firma adı, kademe, kullanılabilir bakiye, günlük limit ve anahtarın kapsamları. mode alanı "live" ya da "test" döner; entegrasyonun ilk isteği bu olmalı. Kapsam İSTEMEZ: hangi kapsamla üretilmiş olursa olsun geçerli her anahtar kendini doğrulayabilir. - GET /bayi-api/v1/balance [balance:read] — Kullanılabilir bakiye. Kullanılabilir bakiye, bloke tutar, onay bekleyen havale toplamı ve kırılım (bakiye + iade edilebilir + bonus). available değeri SİPARİŞ KAPISININ okuduğu ile aynı sayıdır; başka bir toplama yazılsa bot "param var" der ama sipariş INSUFFICIENT_BALANCE yerdi. - GET /bayi-api/v1/balance/transactions [balance:read] — Cari hareketler (imleçli). Cari hareket defteri. Sipariş hareketlerinde tutar EKSİ işaretli döner ve orderId + externalRef alanları dolar; balanceAfter ile mutabakat yapılır. Sayfalama imleçli: yanıttaki nextCursor değerini ?cursor= ile geri gönderin. Sorgu: from, to, type=order|refund|deposit|adjustment|other, cursor, limit ### Katalog & fiyat - GET /bayi-api/v1/catalog/games [catalog:read] — Oyun listesi. Bayiye satılan ürünü olan oyunlar (üst kategoriler), her oyunun altındaki kategoriler (categories) ve ürün sayıları. Ürün listesinde category süzgecine categories[].category verilir. Ürün listesindeki game süzgecine BURADAKİ slug verilir, kategori kimliği değil: kimlikler yönetimde birleştirme sırasında değişebilir, slug adresin parçası olduğu için sabit kalmak zorundadır. - GET /bayi-api/v1/catalog/products [catalog:read] — Ürün listesi (imleçli). Bayi fiyatı, liste fiyatı, stok durumu, adet sınırları, zorunlu alan şeması ve teslim tahmini. type=goldbar ürünlerde delivery.mode=manual gelir (kod dönmez, operatör oyun içi teslim eder) ve deliveryNote teslimat yerini yazar. price SİZİN fiyatınızdır (kademe + size özel istisna uygulanmış), listPrice sitedeki perakende fiyat. ETag döner: sonraki istekte If-None-Match ile gönderin, değişmediyse 304 alırsınız ve gövde harcanmaz. Sorgu: type=epin|topup|goldbar, game, category, q, inStock, updatedSince, cursor, limit - GET /bayi-api/v1/catalog/products/{productId} [catalog:read] — Tek ürün. Tek ürünün tam görünümü. Ürün başına zorunlu alan ŞEMASI burada yayınlanır: alan anahtarları (playerId, server, zoneId, character...) ürün başlıklarından türetilir. Bot bunları uydurmaz, buradan okur; sıra değil ANAHTAR ADI önemlidir. - GET /bayi-api/v1/catalog/prices [catalog:read] — Fiyat/stok dökümü ve delta. Ürün listesinin hafif sürümü: yalnız productId, fiyat, stok, satışta mı. Fiyat senkronu yapan botlar için. ?since verilirse GERÇEK DELTA döner (o tarihten sonra fiyatı/stoğu/durumu değişen ürünler, her satırda gerçek updatedAt). Anlık görüntü henüz oluşmamış bir hesapta süzgeç UYGULANMAZ: tam liste + uyarı notu döner, çünkü boş liste botun "değişim yok" sanıp fiyat senkronunu hiç yapmaması demek olurdu. Sorgu: since, cursor, limit ### Hesap doğrulama - POST /bayi-api/v1/orders/validate [orders:write] — Oyuncu bilgisini önceden doğrula. Top-up ürünlerinde oyuncu bilgisini tedarikçiye ÖNCEDEN sorar; para düşmez. supported=false ise üründe önceden doğrulama yoktur (sipariş vermeyi engellemez). valid=null "şu an kontrol edilemedi" demektir: teknik hata satışı ENGELLEMEZ, aynı kontrol sipariş sırasında çekirdekte tekrar çalışır. Yanıtta requiredFields şeması da döner, böylece hangi alanları göndereceğinizi tek istekte öğrenirsiniz. Örnek gövde: {"productId":1421,"fields":{"playerId":"5123456789","server":"7012"}} ### Sipariş - POST /bayi-api/v1/orders [orders:write] — Sipariş ver. Sipariş verir; tutar bakiyeden düşer. Idempotency-Key başlığı ZORUNLUDUR. Tek istekte en fazla 50 kalem. expectedPrice gönderilirse fiyat değişmişse sipariş VERİLMEZ (PRICE_CHANGED). waitForStock=false ise stok yetmiyorsa hiç başlamaz. Yanıt 201 (sonuç kesin) ya da 202 (teslimat sürüyor). Aynı anahtarla tekrar denerseniz aynı yanıt + Idempotent-Replayed: true başlığı döner, YENİ SİPARİŞ OLUŞMAZ; ağ koptuğunda tekrar göndermek güvenlidir. Örnek gövde: {"externalRef":"SIP-2026-0001","waitForStock":true,"items":[{"productId":6,"quantity":2,"expectedPrice":"98.70"},{"productId":1421,"quantity":1,"fields":{"playerId":"5123456789"}}]} - GET /bayi-api/v1/orders/{orderId} [orders:read] — Sipariş detayı ve kodlar. Sipariş detayı + teslim edilen kodlar. Kodlar YALNIZ bu uçta ve sipariş yanıtında döner; webhook gövdesinde asla gönderilmez. Test modunda verilen siparişlerin kimliği "test_12" biçimindedir ve aynı uçtan okunur. Başka bayinin siparişi 404 döner. - GET /bayi-api/v1/orders/by-ref/{externalRef} [orders:read] — Kendi referansınızla sipariş bul. Bayinin kendi referansıyla sipariş bulur (aynı referansla birden fazla kayıt varsa EN SON kayıt). Ağ hatasından sonra "sipariş düştü mü" sorusunun en hızlı yanıtı budur. Test siparişleri de bu uçtan bulunur. - GET /bayi-api/v1/orders [orders:read] — Sipariş listesi (imleçli). Bayinin siparişleri; panel ve API siparişleri aynı listede (ikisi aynı caridir), channel ile ayrılabilir. productId süzgeci YALNIZ DÖNEN SAYFAYA uygulanır: sipariş içeriği JSON anlık görüntü içinde durduğu için SQL ile aranamaz. Bu durumda yanıtta note alanı çıkar; bot "ürün yok" sanmasın diye susmuyoruz. Sorgu: from, to, status=processing|delivered|partially_delivered|cancelled|failed, channel=dealer-api|dealer-panel, productId, cursor, limit - POST /bayi-api/v1/orders/{orderId}/cancel [orders:write] — Bekleyen kalemleri iptal et. Yalnız BEKLEYEN (processing) kalemleri iptal eder ve tutarı iade alır. Teslim edilmiş kaleme dokunulmaz: kod sizde, kullanılmamış kod iadesi destek kararıdır. İade ve muhasebe işini kanonik teslimat yolu yapar, bu uç ayrı bir iade yolu açmaz. GB (oyun parası) kalemi bu uçtan iptal EDİLEMEZ (NOT_CANCELLABLE): teslimat elle yapıldığı için iade de elle yapılır, destek ekibine yazın. Örnek gövde: {"reason":"Müşteri vazgeçti"} ### Raporlar - GET /bayi-api/v1/reports/statement [balance:read] — Dönem ekstresi (json/csv). Açılış bakiyesi, yükleme/sipariş/iade toplamları, kapanış bakiyesi ve hareket satırları. format=csv doğrudan muhasebe programına verilebilecek dosya döner (BOM ile, noktalı virgül ayırıcı, zarf YOK). Dönemde 5000 satır tavanına ulaşılırsa yanıtta note çıkar; aralığı daraltın. Sorgu: from, to, format=json|csv - GET /bayi-api/v1/invoices [balance:read] — Fatura listesi. Kesilen faturalar: numara, tarih, tutar, KDV ve panel adresi. PDF/UBL indirme bağlantısı henüz API üzerinden VERİLMİYOR (pdfUrl null): sitedeki fatura görüntüleme ucu oturumlu, imzalı ve süresi kısıtlı bir indirme bağlantısı üretmek yeni bir yetkilendirme yüzeyi açmak demek ve bu sürümün kapsamında değil. Belge panelUrl adresinden görüntülenir. Sorgu: from, to ### Webhook'lar - GET /bayi-api/v1/webhooks [webhooks:manage] — Abonelik durumu. Adres, abone olunan olaylar, durum (active|suspended), son başarı/hata damgası, üst üste hata sayacı ve MASKELENMİŞ imza sırrı. Ham sır BU UÇTA DÖNMEZ: jetonu okuyabilen biri sırrı da okuyabilseydi imzanın anlamı kalmazdı. Yanıtta abone olunabilecek olayların katalogu da döner. - GET /bayi-api/v1/webhooks/deliveries [webhooks:manage] — Gönderim kaydı (imleçli). Olay adı, kanal (webhook|email), durum (pending|sent|dead), deneme sayısı, HTTP kodu, süre ve hata metni. Olay GÖVDESİ döndürülmez; gövdeyi ikinci bir yerden yayınlamak gereksiz yüzey olurdu. Yeniden gönderim şu an yalnız Bayi Panelinden yapılır. Yanıtta yeniden deneme tablosu da döner. Sorgu: cursor, limit - PUT /bayi-api/v1/webhooks [webhooks:manage] — Aboneliği oluştur/güncelle. Bayi başına TEK adres olduğu için bu bir "upsert"tir. Adres yalnız https olabilir; localhost ve özel ağ adresleri reddedilir (SSRF). İLK KAYITTA imza sırrı yanıtta BİR KEZ döner, bir daha gösterilmez. Adres değiştirilirse askı (varsa) kalkar. Bilinmeyen olay adı sessizce düşürülmez, 400 ile söylenir: yoksa bot "abone oldum" sanıp olayı beklerdi. events boş gönderilirse varsayılan set uygulanır. POST /webhooks aynı işe bağlıdır. Örnek gövde: {"url":"https://bayi.example.com/oyuneks-hook","events":["order.delivered","order.failed","price.changed","balance.low"]} Eş adres: POST /bayi-api/v1/webhooks - POST /bayi-api/v1/webhooks/rotate-secret [webhooks:manage] — İmza sırrını yenile. Yeni imza sırrı üretir ve BİR KEZ döndürür. Eski sır ANINDA geçersizdir: iki geçerli sır tutmak, sızan sırrı iptal etmeyi anlamsız kılardı. Yeni sırrı yazana kadar gelen olayların imzası doğrulanamaz, bu yüzden dağıtımı hemen yapın. - POST /bayi-api/v1/webhooks/test [webhooks:manage] — Test olayı gönder (ping). "ping" olayını ANINDA gönderir (kuyruğa girmez, yeniden denenmez) ve HTTP sonucunu döndürür. Adres cevap vermezse yanıt YİNE 200 olur, gövdedeki delivered=false bakılır: istek doğru işlendi, gönderim başarısız. 502 döndürmek botu "benim isteğim hatalı" sanmaya iterdi. POST /webhooks/{webhookId}/test aynı işe bağlıdır. Eş adres: POST /bayi-api/v1/webhooks/{webhookId}/test - DELETE /bayi-api/v1/webhooks [webhooks:manage] — Aboneliği sil. Aboneliği siler; kuyrukta bekleyen olaylar ölü işaretlenir. DELETE /webhooks/{webhookId} de kabul edilir; kimlik başka bayiye aitse 404 döner (varlığını sızdırmayız). Silmek yerine olay listesini daraltmak genelde daha iyidir: adres silindiğinde teslim bildirimlerini de kaybedersiniz. Eş adres: DELETE /bayi-api/v1/webhooks/{webhookId} ## Hata kodları - API_KAPALI (HTTP 503, retryable=true): Bayi API servisi geçici olarak kapatıldı (bakım). Bir süre sonra tekrar deneyin; kod tarafında değişiklik gerekmez. - YETKISIZ (HTTP 401, retryable=false): Anahtar yok, geçersiz, iptal edilmiş, IP izinli değil ya da hesap bayi değil. Panelden anahtarı ve IP listesini kontrol edin. Anahtar sızdıysa iptal edip yenisini üretin. - BAYI_ASKIDA (HTTP 403, retryable=false): Bayilik askıya alınmış. Destek ile görüşülmeli; tekrar denemek çözmez. - API_ERISIMI_KAPALI (HTTP 403, retryable=false): Bayilik aktif ama hesapta API erişimi kapalı. Bayi temsilcinizle görüşün; erişim yönetim tarafından açılır. - KAPSAM_YOK (HTTP 403, retryable=false): Anahtar geçerli ama bu uç için gereken yetki kapsamı seçilmemiş. Panelden bu kapsamı içeren yeni bir anahtar üretin (kapsam sonradan eklenemez). - RATE_LIMITED (HTTP 429, retryable=true): İstek tavanı aşıldı. Retry-After başlığındaki saniye kadar bekleyin. Okuma ve yazma tavanları AYRI penceredir. - BAD_REQUEST (HTTP 400, retryable=false): İstek biçimi hatalı: eksik alan, geçersiz değer ya da Idempotency-Key yok. Mesajı okuyup gövdeyi düzeltin; aynı istek tekrarlanırsa aynı hatayı alır. - NOT_FOUND (HTTP 404, retryable=false): Kayıt ya da uç bulunamadı. Kimliği ve adresi doğrulayın. Başka bayinin siparişi de "bulunamadı" döner (varlığını sızdırmayız). - METHOD_NOT_ALLOWED (HTTP 405, retryable=false): Uç bu HTTP metodunu kabul etmiyor. Doğru metot bu sayfadaki uç listesinde yazıyor. - INSUFFICIENT_BALANCE (HTTP 422, retryable=false): Bakiye yetersiz. details.required ve details.available tutarları yanıtta döner. Bakiye yükleyip tekrar deneyin. - PRICE_CHANGED (HTTP 422, retryable=false): Gönderdiğiniz expectedPrice güncel fiyattan farklı; sipariş VERİLMEDİ. details.current güncel fiyatı taşır. Kataloğu tazeleyip yeni fiyatla tekrar deneyin. - OUT_OF_STOCK (HTTP 422, retryable=true): Stok yetersiz (waitForStock=false gönderildi). Bir süre sonra tekrar deneyin ya da waitForStock=true ile kuyruğa alın. - INVALID_FIELDS (HTTP 422, retryable=false): Zorunlu alanlar eksik ya da uzunluk kısıtına uymuyor. details.fields hatalı alanları listeler. Şemayı GET /catalog/products/{productId} ucundan okuyun. - INVALID_PLAYER_ID (HTTP 422, retryable=false): Oyuncu bilgisi tedarikçi tarafında doğrulanamadı. Sipariş öncesi POST /orders/validate ile kontrol edin; müşteriden doğru kimliği isteyin. - LIMIT_EXCEEDED (HTTP 422, retryable=false): Günlük sipariş limiti ya da kalem başına adet tavanı aşıldı. GET /me ucundaki limits alanına bakın; günlük limit gece sıfırlanır. - PRODUCT_DISABLED (HTTP 422, retryable=false): Ürün satışta değil ya da fiyatı tanımlı değil. Kataloğu tazeleyin; ürün geri açıldığında product.enabled olayı gelir. - PRODUCT_NOT_ALLOWED (HTTP 422, retryable=false): Ürün bayi kanalından satılamaz. Bu ürünler katalog uçlarında da listelenmez; sipariş gövdesinden çıkarın. - NOT_CANCELLABLE (HTTP 422, retryable=false): GB (oyun parası) kalemi bu uçtan iptal edilemez; teslimat elle yapılır. İptal için destek ekibine yazın. Aynı siparişteki e-pin/top-up kalemleri normal şekilde iptal edilir. - MIN_QTY (HTTP 422, retryable=false): Ürünün asgari sipariş adedinin altında kalındı. Katalogdaki limits.minQty değerini kullanın. - IDEMPOTENCY_MISMATCH (HTTP 409, retryable=false): Aynı Idempotency-Key daha önce FARKLI bir gövdeyle kullanıldı. Her yeni sipariş için yeni anahtar üretin (kendi sipariş numaranız + deneme sayacı iyi bir kalıp). - ORDER_IN_PROGRESS (HTTP 409, retryable=true): Aynı anahtarla bir sipariş şu an işleniyor. Birkaç saniye bekleyip GET /orders/by-ref/{externalRef} ile sonucu okuyun. - NOT_IMPLEMENTED (HTTP 501, retryable=false): Uç ilan edildi ama henüz çalışmıyor. Şu anda bu kodu döndüren uç YOK; listede tarihsel bütünlük için duruyor. - INTERNAL (HTTP 500, retryable=true): Beklenmeyen sunucu hatası. Tekrar deneyin; sürerse X-Request-Id ile destek kaydı açın. ## Sipariş durumları - processing (son durum: hayır): Ödendi, teslimat sürüyor: stok bekleniyor ya da tedarikçiden çekiliyor. HTTP 202 ile döner. - delivered (son durum: evet): Tüm kalemler teslim edildi (e-pin'de kod, top-up'ta makbuz). - partially_delivered (son durum: evet): Bazı kalemler teslim, bazıları iptal/iade edildi. İade tutarı cari harekette refund olarak görünür. - cancelled (son durum: evet): Bekleyen kalemler iptal edildi ve tutar iade alındı (siz iptal ettiniz ya da destek iptal etti). - failed (son durum: evet): Zaman aşımı: stok verilen süre içinde sağlanamadı, tutar iade edildi. Kalemde failCode=TIMEOUT. ## Webhook olayları - order.delivered: Siparis teslim edildi (kismi teslim de bu olayla gelir) - order.failed: Siparis basarisiz/iptal: tutar bakiyeye iade edildi - price.changed: Bayi fiyatin degisti - stock.changed: Urunun stok durumu degisti - product.enabled: Urun yeniden satista - product.disabled: Urun satistan cikti - balance.low: Bakiye esigin altina dustu - balance.credited: Bakiyene yukleme yapildi - ping: Panelden/API'den "test et" denildiğinde gönderilir. Abonelik gerektirmez, kuyruğa girmez, yeniden denenmez. mode alanı "test" gelir. İmza: t=,v1= — HMAC-SHA256, imzalanan: t + "." + HAM istek gövdesi. JSON'i çözüp yeniden serileştirirseniz imza TUTMAZ; ham gövdeyi kullanın (PHP: file_get_contents("php://input")). Yeniden deneme: 2, 4, 8, 16, 32, 64, 128 dakika (8 deneme). Üst üste 8 ölü olayda adres ASKIYA alınır: gönderim durur, bayiye e-posta + site içi bildirim gider, panelden "Yeniden etkinleştir" gerekir. TESLIM EDILEN KODLAR WEBHOOK GOVDESINDE GONDERILMEZ. Kalemde yalnızca codeCount (kod adedi) bulunur; kodlar GET /bayi-api/v1/orders/{orderId} ucundan çekilir. ## Sürümler - 28.08.2026 v1 — Bayi API yayinda * Katalog, bayi fiyati, stok ve zorunlu alan semasi uclari. * Siparis verme (Idempotency-Key zorunlu), okuma, referansla arama ve bekleyen kalem iptali. * Bakiye, cari hareket, donem ekstresi (json/csv) ve fatura listesi. * Imzali webhook aboneligi: 8 olay + ping testi, gonderim kaydi, imza yenileme. * Test anahtari (oyxb_test_): gercek katalog, gercek akis, para dusmez, TEST- onekli kod doner. * Bu dokuman, OpenAPI 3.1 ve Postman koleksiyonu ayni kaynaktan uretiliyor. * MCP sunucusu (/bayi-api/mcp): yapay zeka istemcileri icin 11 arac. Para harcayan araclar iki adimli onay ister.