Sportsbook entegrasyon rehberi
SwiftBet sportsbook'unu sitenize iframe olarak ekleme ve oyuncu bakiyesini kendi sisteminizde tutarak (seamless wallet) çalıştırma.
Genel akış
- Oyuncu sitenizde sportsbook sayfasını açar. Sunucunuz
POST /api/v1/launchçağırır, tek kullanımlık bir adres alır. - Bu adresi iframe'e verirsiniz. Oyuncu bahis yaptığında SwiftSports cüzdan adresinize debit gönderir; siz bakiyeden düşüp
OKdönersiniz. - Kupon sonuçlandığında (otomatik) SwiftSports credit gönderir: kazançta ödeme tutarı, iadede bahis tutarı, kayıpta 0 tutarlı bildirim.
- 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ık | Değer |
|---|---|
X-Swift-Key | API anahtarınız |
X-Swift-Timestamp | Unix zaman (saniye). ±300 sn dışındaki istekler reddedilir. |
X-Swift-Signature | hex(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');
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.
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']]);
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):
| type | Alanlar | Ne zaman |
|---|---|---|
swift:ready | authenticated | Sportsbook yüklendi |
swift:bet-placed | coupon, balance | Kupon alındı. Üst menüdeki bakiyeyi güncelleyin. |
swift:balance | balance | Bakiye 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-count | count | Kupondaki 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 }
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ı
- Ham istek gövdesini alın; timestamp'in ±300 saniye içinde olduğunu doğrulayın.
X-Swift-Keydeğerini kontrol edin, ardından HMAC imzasını ham gövde üzerinden karşılaştırın.transaction_idiçin veritabanında benzersiz indeks kullanın ve işlemi transaction içinde uygulayın.- İ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)
| code | Anlamı |
|---|---|
INSUFFICIENT_FUNDS | Yetersiz bakiye (oyuncuya "Yetersiz bakiye" gösterilir) |
PLAYER_BLOCKED, PLAYER_NOT_FOUND | Oyuncu bahis yapamaz |
DUPLICATE_TRANSACTION | İşlem zaten işlendi — başarılı sayılır |
TRANSACTION_NOT_FOUND | Rollback için: debit hiç gelmedi — kapanmış sayılır |
INVALID_SIGNATURE ve diğerleri | Reddedildi. 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
- Cüzdan adresi HTTPS, imza doğrulaması ham gövdeyle yapılıyor.
- Aynı
transaction_idiki kez gönderildiğinde bakiye bir kez değişiyor. - Rollback, bilinmeyen debit için
OKveyaTRANSACTION_NOT_FOUNDdönüyor. - Iframe domainleriniz panelde kayıtlı;
swift:bet-placedile üst menü bakiyesi güncelleniyor. - Sunucu saatiniz NTP ile senkron (imza ±300 sn).