Wprowadzenie

Jedno API, wiele źródeł kursów.

ArbiScan agreguje kursy bukmacherów w jednym kontrakcie danych. Wydarzenie zawiera listę źródeł, rynków i wyników wraz z ceną oraz znacznikiem ostatniej aktualizacji.

API jest przeznaczone do integracji serwer–serwer. Klucza nie umieszczaj w kodzie przeglądarki, aplikacji mobilnej ani publicznym repozytorium.

Format i czas

  • HTTPS oraz application/json; charset=utf-8.
  • Znaczniki czasu w UTC, zapis ISO-8601.
  • Kursy dziesiętne jako liczby większe od 1.0.
  • Brakujące dane są pomijane, a nie zastępowane wartością zerową.

Uwierzytelnianie

Poza endpointem /health każde zapytanie wymaga klucza w nagłówku:

X-API-Key: ods_your_key

Zasady bezpieczeństwa

  • Wczytuj klucz ze zmiennej środowiskowej lub menedżera sekretów.
  • Plan API Data Plus udostępnia trzy oddzielne klucze dla środowisk.
  • Usuń klucz z panelu natychmiast po podejrzeniu wycieku.
  • Nie przesyłaj klucza w query stringu.

Pierwszy request

Zacznij od listy sportów, a następnie pobierz kursy dla wybranej dyscypliny. Poprawna odpowiedź zawiera events i bieżące wykorzystanie limitu.

  1. Utwórz klucz w panelu po aktywacji planu i zapisz go w bezpiecznym miejscu. Istniejące konta mogą zachować swój dotychczasowy klucz.
  2. Ustaw go jako zmienną ARBISCAN_API_KEY.
  3. Wykonaj kod z panelu po prawej stronie.
  4. Zapisz snapshot we własnej bazie i kontroluj last_update.

Limity i kwoty

Limity są przypisane do konta, a nie do pojedynczego klucza. Wszystkie klucze konta współdzielą tę samą pulę minutową i dzienną.

PlanLimit kontaZakres
API Data30 / min · 10 000 / dzień · 1 kluczCały aktywny feed prematch
API Data Plus180 / min · 100 000 / dzień · 3 kluczeFeed + historia 48 h + 1 WebSocket + 3 webhooki

Endpoint /usage nie zużywa kwoty danych; ma osobny limit ochronny 30 odczytów na minutę. Odpowiedzi zawierają X-Request-ID, a przy HTTP 429 także Retry-After.

GET

/health

Publiczny stan feedu. Nie wymaga klucza i nie zużywa kwoty.

PoleTypOpis
okbooleanCzy usługa odpowiada poprawnie.
data_freshbooleanCzy istnieje co najmniej jedno przyszłe wydarzenie ze świeżym wydarzeniem i kursem.
data_statusstringfresh albo degraded; oddziela gotowość danych od dostępności procesu.
fresh_events_knownintegerLiczba wydarzeń w aktywnym oknie świeżości.
last_ingestdatetimeCzas ostatniego przyjętego snapshotu.
active_max_age_secondsintegerMaksymalny wiek aktywnych danych.
GET

/sports

Zwraca kanoniczne nazwy sportów obecnych w świeżym snapshotcie.

{ "sports": ["Football", "Tennis", "Volleyball"] }
GET

/leagues

Lista rozgrywek. Opcjonalnie ogranicz wynik do jednego sportu.

ParametrTypOpis
sportstringKanoniczna nazwa z endpointu /sports.
GET

/bookmakers

Zwraca źródła mające co najmniej jeden świeży kurs w bieżącym feedzie.

{ "bookmakers": ["Betclic", "Fortuna", "STS", "Superbet"] }
GET

/markets

Katalog świeżych rynków dostępnych w feedzie wraz z liczbą wydarzeń i bukmacherów. Klucze linii mają postać rynek|specifier, np. totals|2.5.

ParametrTypOpis
sportstringOpcjonalny filtr dyscypliny.
leaguestringOpcjonalny filtr rozgrywek.
bookmakerstringOpcjonalny filtr jednego bukmachera.
limitinteger1–2000 pozycji, domyślnie 500.
cursorstringNieprzezroczysty kursor kolejnej strony.
GET

/odds

Główny endpoint integracyjny. Zwraca wydarzenia wraz z aktualnymi bukmacherami, rynkami i wynikami.

ParametrTypOpis
sportstringFiltr po kanonicznej nazwie sportu.
leaguestringFiltr po nazwie rozgrywek, bez rozróżniania wielkości liter.
bookmakerscsvNp. STS,Fortuna,Superbet.
marketscsvDokładne klucze z endpointu /markets.
commence_fromISO-8601Dolna granica czasu rozpoczęcia.
commence_toISO-8601Górna granica czasu rozpoczęcia.
max_age_secondsintegerMaksymalny wiek kursu: 60–900 sekund, domyślnie 900.
limitintegerMaksymalnie 500 wydarzeń, domyślnie 200.
cursorstringNieprzezroczysty kursor z pola next_cursor poprzedniej strony.
Publiczny feed jest wyłącznie przedmeczowy. Parametr max_age_seconds przyjmuje 60–900 sekund, a nieaktualne oferty nie są zwracane.

Odpowiedź

  • count — liczba wydarzeń w odpowiedzi.
  • events[] — wydarzenia i kursy.
  • has_more — czy istnieje następna strona.
  • next_cursor — kursor następnej strony albo null.
  • snapshot — identyfikator, czas i publication_generation spójnego widoku; generacja zmienia się także po przyjętym pushu częściowym.
  • freshness — tryb zwracania zapisanych kursów.
  • quota — limity dzienne i łączne.
GET

/events/{event_id}

Pobiera jedno wydarzenie ze wszystkimi rynkami obecnymi w aktywnym oknie świeżości.

ParametrTypOpis
event_idpathIdentyfikator zwrócony przez /odds.
GET

/events/{event_id}/history

Do 48 godzin zaobserwowanych zmian kursów jest dostępne wyłącznie w planie API Data Plus. Historia zapisuje pierwszą obserwację i zmiany ceny, a nie próbki w stałym interwale. Plan API Data otrzyma HTTP 403 plan_upgrade_required.
ParametrTypOpis
marketstringDokładny klucz rynku; domyślnie h2h.
bookmakerstringOpcjonalny dokładny filtr bukmachera.
since / untilISO-8601Opcjonalne granice czasu obserwacji.
limitinteger1–5000 zmian, domyślnie 1000.
cursorstringNieprzezroczysty kursor kolejnej strony. Nie zmieniaj filtrów między stronami.

Odpowiedź zawiera observed_from, observed_until, has_more i next_cursor. Pobieraj strony aż has_more=false.

WS

/stream

Strumień zmian kursów dla API Data Plus. Połącz się z wss://api.arbiscan.pl/v1/stream i przekaż klucz wyłącznie w nagłówku X-API-Key. Jest to interfejs serwer–serwer; przeglądarkowy WebSocket nie pozwala ustawić tego nagłówka bez backendowego proxy.

ParametrTypOpis
cursorintegerOpcjonalny identyfikator ostatniej przetworzonej zmiany. Bez niego strumień zaczyna od bieżącego końca historii.
sportscsvDo 20 nazw sportów, bez rozróżniania wielkości liter.
bookmakerscsvDo 20 nazw bukmacherów.
X-API-Key: ods_your_plus_key

Pierwszy komunikat ma typ ready. Zmiany przychodzą jako odds.changed w paczkach do 50 rekordów, najwyżej raz na sekundę. Po 20 sekundach bez zmian serwer wysyła heartbeat. Konto może utrzymywać jedno aktywne połączenie; kolejne jest zamykane kodem polityki WebSocket 1008.

API

/webhooks

API Data Plus może zarejestrować maksymalnie trzy publiczne adresy HTTPS. Obsługiwane zdarzenia to odds.changed i snapshot.updated.

OperacjaŚcieżkaZnaczenie
GET/webhooksLista konfiguracji bez sekretów podpisu.
POST/webhooksTworzy webhook; sekret podpisu jest ujawniany tylko raz.
POST/webhooks/{id}/testKolejkuje bezpieczny komunikat testowy.
DELETE/webhooks/{id}Wyłącza dalsze dostawy.
{ "url": "https://example.com/arbiscan", "events": ["odds.changed"] }

Weryfikacja podpisu

Oblicz HMAC-SHA256 z tekstu {timestamp}.{raw_body} przy użyciu sekretu zwróconego przy tworzeniu. Porównaj wynik ze składnikiem v1 nagłówka X-ArbiScan-Signature i odrzuć stare timestampy. Identyfikator zdarzenia jest w X-ArbiScan-Event-ID; zapisuj go, aby retry było idempotentne.

Timeout dostawy wynosi 5 sekund. Nieudana dostawa ma maksymalnie cztery próby: pierwszą od razu, następne po około 1, 5 i 30 minutach. Dziesięć kolejnych ostatecznie nieudanych zdarzeń wyłącza adres.

GET

/usage

Raportuje użycie bieżącego klucza z ostatnich 30 dni bez zużywania kwoty danych.

PoleTypOpis
todayobjectWykorzystanie i limit dzienny.
totalobjectWykorzystanie, limit łączny i pozostała pula.
expires_atdatetime|nullTermin ważności klucza.
historyarrayDzienne użycie z ostatnich 30 dni.

Schemat wydarzenia

Każde wydarzenie opisuje dyscyplinę, rozgrywki, uczestników, czas rozpoczęcia i listę bukmacherów. Bukmacher zawiera rynki, a rynek — wyniki z ceną i czasem aktualizacji.

event → bookmakers[] → markets[] → outcomes[]

Pola last_update są dostępne na poziomie bukmachera, rynku i pojedynczego wyniku. Przy synchronizacji wybieraj najbardziej szczegółowy znacznik czasu.

Błędy HTTP

KodZnaczenieReakcja klienta
400Nieprawidłowe parametry.Popraw request, nie ponawiaj automatycznie.
401Brak, wygasły lub wyłączony klucz.Sprawdź sekret albo skontaktuj się z administratorem.
403Funkcja nie należy do planu.Sprawdź zakres planu lub przejdź na Data Plus.
404Nie znaleziono wydarzenia.Usuń rekord z lokalnej kolejki odświeżania.
410Funkcja jest wyłączona.Nie ponawiaj do czasu zmiany planu.
409Snapshot zmienił się podczas paginacji.Rozpocznij pobieranie od pierwszej strony.
429Przekroczono limit.Odczytaj limit i odczekaj; nie zapętlaj retry.
5xxBłąd usługi.Zastosuj ograniczony exponential backoff.

Integracja produkcyjna

  • Pobieraj dane cyklicznie z backendu i zapisuj ostatni poprawny snapshot.
  • Ustaw timeout, ograniczoną liczbę retry i jitter.
  • Porównuj last_update przed nadpisaniem rekordu.
  • Pobieraj kolejne strony, przekazując next_cursor jako parametr cursor, aż has_more=false.
  • Traktuj WebSocket i webhooki jako kanał zmian, a REST jako źródło pełnej synchronizacji oraz naprawy przerw.
  • Webhooki weryfikuj na surowym body, podpisie HMAC, świeżym timestampie i idempotentnym identyfikatorze zdarzenia.
  • Jeśli kolejna strona zwróci HTTP 409 snapshot_changed, rozpocznij spójną paginację od początku.
  • Monitoruj /health, ale nie traktuj samego HTTP 200 jako gwarancji świeżości.
  • Nie przekazuj klucza użytkownikom końcowym.

Kompletna specyfikacja maszynowa jest dostępna jako OpenAPI 3.1 JSON.