Sportsbook entegrasyon rehberi

SwiftBet sportsbook'unu sitenize iframe olarak ekleme ve oyuncu bakiyesini kendi sisteminizde tutarak (seamless wallet) çalıştırma.

Sunucudan sunucuya entegrasyonAPI anahtarı ve gizli anahtar yalnız backend'inizde kalır. Tarayıcı launch çağrısı yapmaz; sadece backend'inizin aldığı tek kullanımlık URL'yi iframe içinde açar.
01 · HazırlaWallet endpoint'inizi ve HMAC doğrulamasını oluşturun.
02 · BağlaLaunch API'den URL alıp iframe'e yerleştirin.
03 · DoğrulaDebit, credit, rollback ve tekrar gönderim testlerini tamamlayın.

Genel akış

  1. Oyuncu sitenizde sportsbook sayfasını açar. Sunucunuz POST /api/v1/launch çağırır, tek kullanımlık bir adres alır.
  2. Bu adresi iframe'e verirsiniz. Oyuncu bahis yaptığında SwiftSports cüzdan adresinize debit gönderir; siz bakiyeden düşüp OK dönersiniz.
  3. Kupon sonuçlandığında (otomatik) SwiftSports credit gönderir: kazançta ödeme tutarı, iadede bahis tutarı, kayıpta 0 tutarlı bildirim.
  4. Bir debit'in sonucu belirsiz kalırsa (zaman aşımı) SwiftSports kuponu kaydetmez ve rollback gönderir.

Bakiye her zaman sizdedir. SwiftSports oyuncu parası tutmaz.

İmzalama

İki yöndeki tüm çağrılar aynı gizli anahtarla (panel → Entegrasyon) HMAC-SHA256 ile imzalanır.

BaşlıkDeğer
X-Swift-KeyAPI anahtarınız
X-Swift-TimestampUnix zaman (saniye). ±300 sn dışındaki istekler reddedilir.
X-Swift-Signaturehex(hmac_sha256(gizli_anahtar, timestamp + "." + gövde)). GET isteklerinde gövde yerine sorgu dizesi (? sonrası, gönderildiği haliyle).
// PHP
$body = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$ts = (string) time();
$sig = hash_hmac('sha256', $ts . '.' . $body, $secret);

// Node.js
const body = JSON.stringify(payload);
const ts = String(Math.floor(Date.now() / 1000));
const sig = crypto.createHmac('sha256', secret).update(ts + '.' + body).digest('hex');
Cüzdan adresinize gelen çağrılarda imzayı ham gövde üzerinden doğrulayın (JSON'u çözüp yeniden üretmeyin) ve hash_equals / timingSafeEqual ile karşılaştırın.

Launch

POSThttps://swiftsports.site/api/v1/launch

{
  "player_id": "84512",          // sizdeki oyuncu kimliği (zorunlu)
  "username": "ali_k",           // panelde görünen ad (zorunlu)
  "currency": "TRY",             // bayi para biriminiz
  "language": "tr",
  "device": "desktop",           // desktop | mobile
  "lobby_url": "https://www.siteniz.com/spor",  // iframe'in açıldığı sayfa (mesaj kökeni için)
  "is_test": false
}
200 OK
{ "status": "OK", "url": "https://swiftsports.site/play/8yQ...", "expires_in": 120 }

Adres 2 dakika içinde ve bir kez açılabilir. Her sayfa açılışında yeni adres alın. Oturum 12 saat hareketsizlikte kapanır.

Her yeni launch isteğinin JSON gövdesine benzersiz bir request_id (ör. UUID) ekleyin ve bu alanı içeren ham gövdeyi imzalayın. Aynı timestamp ve imzayla tekrar gönderilen launch isteği 401 REQUEST_REPLAYED döndürür. GET mutabakat istekleri bu kısıtın dışındadır.

Backend'den launch çağrısı — PHP

<?php
$payload = [
    'request_id' => (string) bin2hex(random_bytes(16)),
    'player_id' => (string) $user->id,
    'username' => $user->username,
    'currency' => 'TRY',
    'language' => 'tr',
    'device' => $isMobile ? 'mobile' : 'desktop',
    'lobby_url' => 'https://www.siteniz.com/spor',
];
$body = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
$ts = (string) time();
$signature = hash_hmac('sha256', $ts.'.'.$body, $_ENV['SWIFT_SECRET']);

$response = Http::withHeaders([
    'X-Swift-Key' => $_ENV['SWIFT_API_KEY'],
    'X-Swift-Timestamp' => $ts,
    'X-Swift-Signature' => $signature,
])->withBody($body, 'application/json')
  ->post('https://swiftsports.site/api/v1/launch')
  ->throw()->json();

return view('sportsbook', ['launchUrl' => $response['url']]);
Launch endpoint'ini kendi oturum kontrolünüzün arkasında tutun. player_id değerini tarayıcıdan olduğu gibi kabul etmeyin; giriş yapmış kullanıcıdan üretin.

Iframe ve olaylar

<iframe id="swiftsports" src="{url}" style="width:100%;height:100vh;border:0" allow="fullscreen"></iframe>

Iframe yalnız panelde kayıtlı domainlerinizde açılır. Sportsbook, sayfanıza postMessage ile şu olayları gönderir (kaynak: https://swiftsports.site):

typeAlanlarNe zaman
swift:readyauthenticatedSportsbook yüklendi
swift:bet-placedcoupon, balanceKupon alındı. Üst menüdeki bakiyeyi güncelleyin.
swift:balancebalanceBakiye değişti / yenilendi
swift:login-required—Misafir oyuncu bahis yapmak istedi
swift:session-expired—Oturum süresi doldu; yeni launch adresi alın
swift:betslip-countcountKupondaki seçim sayısı

Sayfanızdan iframe'e {type:'swift:refresh-balance'} göndererek bakiyeyi hemen yeniletebilirsiniz (ör. para yatırma sonrası).

Seamless wallet

Panelde tanımladığınız adrese POST, JSON gövde ve yukarıdaki imza başlıklarıyla gelir. Her çağrıda action alanı işlemi belirtir. Cevabınız her zaman JSON olmalıdır:

// Başarılı
{ "status": "OK", "balance": 1250.50, "transaction_id": "sizdeki-islem-no" }
// Hata
{ "status": "ERROR", "code": "INSUFFICIENT_FUNDS", "message": "Yetersiz bakiye", "balance": 20.00 }
İdempotentlik zorunludur. Aynı transaction_id ikinci kez gelirse işlemi tekrar uygulamayın; ilk sonucu (OK) dönün. Credit ve rollback, siz OK dönene kadar yeniden gönderilir.

Wallet endpoint kontrol sırası

  1. Ham istek gövdesini alın; timestamp'in ±300 saniye içinde olduğunu doğrulayın.
  2. X-Swift-Key değerini kontrol edin, ardından HMAC imzasını ham gövde üzerinden karşılaştırın.
  3. transaction_id için veritabanında benzersiz indeks kullanın ve işlemi transaction içinde uygulayın.
  4. İlk başarılı cevabı saklayın; tekrar gelen aynı işlemde bakiyeyi değiştirmeden aynı cevabı döndürün.

balance

{ "action": "balance", "player_id": "84512", "currency": "TRY", "timestamp": 1777000000 }

debit — kupon alınırken

{
  "action": "debit",
  "transaction_id": "9b2f8c3e-...",
  "player_id": "84512", "currency": "TRY",
  "amount": "100.00",
  "round_id": "SW1777000000ABC",          // kupon numarası
  "details": { "type": "combined", "total_odds": 4.35, "possible_win": 435.0,
               "selections": [ { "event": "Galatasaray - Fenerbahçe", "market": "Maç Sonucu", "pick": "1", "odds": 2.1, "live": false } ] },
  "timestamp": 1777000000
}

Bakiyeyi düşüp OK dönün. Reddederseniz kupon alınmaz. Cevap 8 sn içinde gelmezse (panelden ayarlanabilir) kupon alınmaz ve aynı debit için rollback gönderilir.

credit — kupon sonuçlandığında

{
  "action": "credit",
  "transaction_id": "e41a...", "reference_transaction_id": "9b2f8c3e-...",   // debit'in kimliği
  "player_id": "84512", "currency": "TRY",
  "amount": "435.00",                     // kayıpta "0.00"
  "result": "won",                        // won | void | lost
  "round_id": "SW1777000000ABC",
  "timestamp": 1777003600
}

amount kadar bakiyeye ekleyin. lost bildirimi 0 tutarlıdır; turu kapatmak içindir.

rollback

{ "action": "rollback", "transaction_id": "77c0...", "reference_transaction_id": "9b2f8c3e-...",
  "player_id": "84512", "currency": "TRY", "amount": "100.00", "timestamp": 1777000010 }

Referans debit'i uyguladıysanız tutarı iade edin. Debit size hiç ulaşmadıysa OK veya {"status":"ERROR","code":"TRANSACTION_NOT_FOUND"} dönün; ikisi de kapanmış sayılır.

Hata kodları (sizin dönebileceğiniz)

codeAnlamı
INSUFFICIENT_FUNDSYetersiz bakiye (oyuncuya "Yetersiz bakiye" gösterilir)
PLAYER_BLOCKED, PLAYER_NOT_FOUNDOyuncu bahis yapamaz
DUPLICATE_TRANSACTIONİşlem zaten işlendi — başarılı sayılır
TRANSACTION_NOT_FOUNDRollback için: debit hiç gelmedi — kapanmış sayılır
INVALID_SIGNATURE ve diğerleriReddedildi. Credit/rollback'te yeniden denenir.

HTTP 5xx, zaman aşımı veya JSON olmayan cevap "bilinmiyor" sayılır.

Kupon sorgulama (mutabakat)

GET/api/v1/bets?from=2026-10-01&to=2026-10-31&status=won&player_id=84512&page=1&per_page=50

GET/api/v1/bets/{kupon_no}

{ "status": "OK", "bet": { "coupon": "SW1777000000ABC", "player_id": "84512", "stake": 100, "total_odds": 4.35,
  "possible_win": 435, "status": "won", "payout": 435, "placed_at": "2026-10-26T20:15:00+03:00", "selections": [ ... ] } }

Test modu

Yeni bayiler test modunda açılır: cüzdan çağrıları sitenize gitmez, her oyuncu 10.000 sanal bakiye ile oynar. Launch API ve iframe aynı şekilde çalışır. Panel → Entegrasyon → Önizleme ile hemen deneyebilirsiniz.

Canlıya geçiş listesi