PRO VÝVOJÁŘE

Autorizované Data API

Serverové read-only rozhraní nad připravenými veřejnými daty Streamers.cz. Každý datový požadavek vyžaduje krátkodobý Bearer token, shodné Client-Id a nejmenší potřebný scope.

Data API není anonymní browserové API. Client Secret ani token nevkládejte do URL, HTML, veřejného JavaScriptu nebo místního úložiště prohlížeče. Volání provádějte ze svého serveru.

Rychlý začátek

Od aplikace k první stránce dat

Data API používá OAuth 2.0 client credentials tok. Není propojený s přihlášením uživatele, administrátorským OAuth ani tokeny Twitche či Kicku.

  1. Založte aplikaci

    V dashboardu vyberte jen potřebné scopes. Client Secret uložte hned; zobrazí se pouze při vytvoření nebo rotaci.

  2. Získejte token

    Po schválení aplikace odešlete POST /oauth2/token jako application/x-www-form-urlencoded. Přihlašovací údaje patří výhradně do těla.

  3. Pošlete dvě hlavičky

    Každý datový request musí obsahovat Authorization: Bearer … a Client-Id: …. Client ID se musí shodovat s tokenem.

  4. Pokračujte kurzorem

    Pokud je has_more=true, pošlete beze změny vrácený next_cursor se stejnými filtry. Při 429 respektujte Retry-After.

Autorizace

Token, validace a revokace

Token je krátkodobý a opaque: klient z něj nemá nic dekódovat. Jeho oprávnění a zbývající platnost ověří autorizační služba.

POST /oauth2/token

Tělo obsahuje přesně grant_type=client_credentials, client_id, client_secret a mezerami oddělený scope. HTTP Basic ani credentials v query stringu nepodporujeme.

GET /oauth2/validate

Pošlete běžné hlavičky Bearer a Client-Id. Odpověď vrátí client_id, pole scopes a expires_in.

POST /oauth2/revoke

Odvolá právě použitý Bearer token. Token se záměrně neposílá v těle ani URL. Úspěšná odpověď má stav 200 a {"revoked":true}.

Obnova tokenu

Client credentials token nemá refresh token. V dostatečném předstihu si server vyžádá nový access token a starý po bezpečném přechodu odvolá.

curl -X POST "https://streamers.cz/oauth2/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=client_credentials" \
--data-urlencode "client_id=$STREAMERS_CLIENT_ID" \
--data-urlencode "client_secret=$STREAMERS_CLIENT_SECRET" \
--data-urlencode "scope=streamers:read streams:read"

Oprávnění

Scopes a bodová cena

Žádejte pouze oprávnění, která aplikace skutečně používá. Schválený scope neotevírá jiný endpoint ani soukromá pole.

ScopeOblastCo dovolujeBody
streamers:read Streamery Katalog samostatných Twitch a Kick účtů. 1
streams:read Streamy Živé a dokončené streamy z připravené historie. 1
users:read Uživatelé Zveřejněné uživatelské karty a jejich veřejná pole. 1
categories:read Kategorie Připravené agregace kategorií. 1
rankings:read Žebříčky Finalizované generace žebříčků. 1
clips:read Klipy Veřejný katalog a detail klipu. 1 / 2
statistics:read Statistiky Malý připravený souhrn scény. 1
teams:read Týmy Veřejné Twitch týmy a způsobilí CZ/SK členové. 1
search:read Hledání Omezené hledání v připravených indexech. 2

Reference

Podporovaný katalog endpointů

Publikujeme jednu kanonickou sadu bez paralelních produktových verzí. OpenAPI uvádí přesné enumy, maxima, response schémata a příklady.

EndpointScopeStránkaPoužití
GET /api/streamers.php streamers:read výchozí 50, maximum 100 Filtrovaný katalog platformních účtů. Propojený Twitch a Kick profil se zde nikdy nesčítá do jednoho řádku.
GET /api/streams.php streams:read výchozí 30, maximum 60 Živá a dokončená vysílání. today až 14d používá hot katalog, delší období atomicky publikovanou historii.
GET /api/users.php users:read výchozí 30, maximum 50 Pouze uživatelem zveřejněné karty. Soukromé nastavení, e-mail ani propojené interní identity API nevrací.
GET /api/categories.php categories:read výchozí 30, maximum 100 Kategorie a předpočítané metriky podle období. lifetime znamená zachycenou historii Streamers.cz, nikoli celou historii platformy.
GET /api/rankings.php rankings:read výchozí 50, maximum 100 Finalizované pořadí pro jednu metriku a období. Twitch a Kick používají stejnou metodiku, ale každý účet zůstává samostatný.
GET /api/clips.php clips:read výchozí 24, maximum 200 Katalog klipů nebo detail podle clip slugu. Textové hledání a náhodné řazení stojí 2 body; u náhodného řazení pokračujte pouze serverem vráceným shuffle seedem.
GET /api/public-stats.php statistics:read bez parametrů Malý připravený snapshot souhrnných hodnot. Endpoint nepočítá libovolné vlastní rozsahy během požadavku.
GET /api/teams.php teams:read výchozí 36, rozsah 12–72 Adresář Twitch týmů nebo detail jejich veřejné CZ/SK části. Seznam members obsahuje jen způsobilé veřejné účty, které Streamers.cz skutečně eviduje; není to úplná oficiální soupiska.
GET /api/search.php search:read omezený připravený výsledek Hledá streamery, veřejné karty, kategorie a týmy. Striktní shoda identity má přednost před popularitou.

Streamery

GET /api/streamers.php

Filtrovaný katalog platformních účtů. Propojený Twitch a Kick profil se zde nikdy nesčítá do jednoho řádku.

Scope
streamers:read
Velikost stránky
výchozí 50, maximum 100
Parametry
q (160), platform, category (180), type (64), tag (80), status, language, partner, sort, dir, číselné rozsahy, limit, pagination=cursor, cursor

Datové endpointy vyžadují současně hlavičky Authorization a Client-Id. Úplný parametrický a response kontrakt je v OpenAPI.

Streamy

GET /api/streams.php

Živá a dokončená vysílání. today až 14d používá hot katalog, delší období atomicky publikovanou historii.

Scope
streams:read
Velikost stránky
výchozí 30, maximum 60
Parametry
platform, period, month, streamer (64), status, language, category (180), type (64), sort, limit, cursor

Datové endpointy vyžadují současně hlavičky Authorization a Client-Id. Úplný parametrický a response kontrakt je v OpenAPI.

Uživatelé

GET /api/users.php

Pouze uživatelem zveřejněné karty. Soukromé nastavení, e-mail ani propojené interní identity API nevrací.

Scope
users:read
Velikost stránky
výchozí 30, maximum 50
Parametry
q (120), platform, sort=az|live, dir, limit, cursor

Datové endpointy vyžadují současně hlavičky Authorization a Client-Id. Úplný parametrický a response kontrakt je v OpenAPI.

Kategorie

GET /api/categories.php

Kategorie a předpočítané metriky podle období. lifetime znamená zachycenou historii Streamers.cz, nikoli celou historii platformy.

Scope
categories:read
Velikost stránky
výchozí 30, maximum 100
Parametry
q (100), platform, scope=live|all, period, month, sort, dir, limit, cursor

Datové endpointy vyžadují současně hlavičky Authorization a Client-Id. Úplný parametrický a response kontrakt je v OpenAPI.

Žebříčky

GET /api/rankings.php

Finalizované pořadí pro jednu metriku a období. Twitch a Kick používají stejnou metodiku, ale každý účet zůstává samostatný.

Scope
rankings:read
Velikost stránky
výchozí 50, maximum 100
Parametry
metric, period, month, limit, cursor

Datové endpointy vyžadují současně hlavičky Authorization a Client-Id. Úplný parametrický a response kontrakt je v OpenAPI.

Klipy

GET /api/clips.php

Katalog klipů nebo detail podle clip slugu. Textové hledání a náhodné řazení stojí 2 body; u náhodného řazení pokračujte pouze serverem vráceným shuffle seedem.

Scope
clips:read
Velikost stránky
výchozí 24, maximum 200
Parametry
clip (260), q (120), platform, platform_user_id (128), period, category (128), duration, language, type, sort, dir, shuffle, limit, cursor

Datové endpointy vyžadují současně hlavičky Authorization a Client-Id. Úplný parametrický a response kontrakt je v OpenAPI.

Statistiky

GET /api/public-stats.php

Malý připravený snapshot souhrnných hodnot. Endpoint nepočítá libovolné vlastní rozsahy během požadavku.

Scope
statistics:read
Velikost stránky
bez parametrů
Parametry
žádné

Datové endpointy vyžadují současně hlavičky Authorization a Client-Id. Úplný parametrický a response kontrakt je v OpenAPI.

Týmy

GET /api/teams.php

Adresář Twitch týmů nebo detail jejich veřejné CZ/SK části. Seznam members obsahuje jen způsobilé veřejné účty, které Streamers.cz skutečně eviduje; není to úplná oficiální soupiska.

Scope
teams:read
Velikost stránky
výchozí 36, rozsah 12–72
Parametry
q (100), team (128), sort, limit, cursor

Datové endpointy vyžadují současně hlavičky Authorization a Client-Id. Úplný parametrický a response kontrakt je v OpenAPI.

Stránkování

Cursor je pokračování, ne číslo stránky

Rostoucí katalogy používají opaque keyset cursor. Díky tomu request nepřeskakuje všechny předchozí řádky ani při stovkách tisíc účtů.

První stránka

Pošlete filtry a limit bez cursoru. U streamerů přidejte pagination=cursor.

Další stránka

Pokračujte jen tehdy, když je has_more=true a odpověď obsahuje neprázdný next_cursor.

Stejné filtry

Cursor je podepsaný pro konkrétní řazení, filtry a generaci. Se změněnými parametry správně skončí chybou 422.

Nový výběr

Při změně filtru nebo po expiraci generace začněte bez cursoru. Cursor neupravujte, nedekódujte a nevytvářejte vlastní offset.

Kvóty

Limity jsou bodové

Běžné čtení stojí 1 bod; globální hledání a klipové textové či náhodné dotazy 2 body. Výchozí schválená aplikace má zpravidla 120 bodů za minutu a 20 000 za den; rozhodující jsou limity z dashboardu a odpovědních hlaviček.

Ratelimit-Limit
Velikost aktuálního minutového bodového okna.
Ratelimit-Remaining
Zbývající body po právě dokončeném requestu.
Ratelimit-Reset
Unix timestamp resetu minutového okna.
Ratelimit-Policy
Strojově čitelná minutová a denní politika.
Retry-After
Přesný počet sekund pro další pokus po 429.

Při 429 request automaticky neopakujte ve smyčce. Počkejte podle Retry-After, přidejte jitter a na 5xx použijte omezený exponenciální backoff.

Čerstvost dat

Response není živý dotaz na platformu

Endpointy čtou hotové cache, indexy nebo finalizované generace. Opakovaný request proto nevynutí novější data.

Live data

Průběžně se mění podle posledního skutečně zachyceného stavu. Nemusí odpovídat každé sekundě platformy.

Dokončené období

Žebříčky a delší agregace se publikují až jako úplná generace. Do té doby zůstává čitelná předchozí hotová verze.

Časové hranice

Výměna dat používá UTC. Produktová období a dokončené dny se vyhodnocují v Europe/Prague včetně DST.

Historické mezery

Chybějící měření není nula a nedopočítává se. lifetime znamená zachycenou historii od 1. 5. 2026 nebo pozdějšího zařazení účtu.

Výkonnostní pravidlo: veřejný request nikdy neskenuje FTP archiv, nestahuje celý katalog ani nevolá Twitch či Kick. Náročné přepočty probíhají mimo veřejnou obsluhu.

Chyby

Jednotný strojově čitelný tvar

Uložte si request_id, ale nikdy k němu nepřidávejte token, secret ani celou URL s citlivými údaji.

{
"error": {
"status": 403,
"code": "insufficient_scope",
"message": "The access token does not grant the required scope.",
"request_id": "req_...",
"required_scope": "rankings:read",
"docs_url": "https://streamers.cz/developers#errors"
}
}

HTTPKódCo znamená
400 invalid_request Přihlašovací údaj byl v URL, chybí povinné pole nebo má požadavek chybný formát.
400 unsupported_grant_type Token endpoint podporuje jen grant_type=client_credentials.
400 invalid_scope Požadovaný scope neexistuje nebo nebyl aplikaci schválen.
401 invalid_client Client ID, Client Secret nebo stav aplikace není platný.
401 invalid_token Bearer token chybí, vypršel, byl odvolán nebo nepatří Client ID.
403 insufficient_scope Token je platný, ale endpoint vyžaduje jiný scope. Odpověď obsahuje required_scope.
404 not_found Požadovaný veřejný detail neexistuje nebo už není zveřejněný.
410 gone / generation_expired Kurzor odkazuje na generaci, která už není dostupná.
422 invalid_parameter Filtr, kombinace parametrů nebo cursor není platný.
429 rate_limited Došly body. Řiďte se Retry-After a Ratelimit-Reset.
429 token_limit_reached Aplikace už má maximální počet aktivních tokenů; jeden z nich nejdříve odvolejte.
503 service_unavailable Autorizace, limiter nebo bezpečně publikovaný read model není dočasně dostupný.

Příklady

Serverové použití v běžných jazycích

Ukázky čtou credentials z prostředí. V produkci kontrolujte HTTP stav, timeout, JSON chybu, rate-limit hlavičky a bezpečně obnovujte token před expirací.

cURL

curl "https://streamers.cz/api/streamers.php?platform=twitch&limit=50&pagination=cursor" \
-H "Authorization: Bearer $STREAMERS_ACCESS_TOKEN" \
-H "Client-Id: $STREAMERS_CLIENT_ID"

PHP

<?php
$clientId = getenv('STREAMERS_CLIENT_ID');
$clientSecret = getenv('STREAMERS_CLIENT_SECRET');

$form = http_build_query([
'grant_type' => 'client_credentials',
'client_id' => $clientId,
'client_secret' => $clientSecret,
'scope' => 'streamers:read',
], '', '&', PHP_QUERY_RFC3986);

$tokenResponse = file_get_contents('https://streamers.cz/oauth2/token', false, stream_context_create([
'http' => [
'method' => 'POST',
'header' => "Content-Type: application/x-www-form-urlencoded\r\n",
'content' => $form,
'timeout' => 10,
'ignore_errors' => true,
],
]));
$token = json_decode((string) $tokenResponse, true, 32, JSON_THROW_ON_ERROR);

$dataResponse = file_get_contents(
'https://streamers.cz/api/streamers.php?limit=50&pagination=cursor',
false,
stream_context_create(['http' => [
'header' => "Authorization: Bearer {$token['access_token']}\r\nClient-Id: {$clientId}\r\n",
'timeout' => 10,
'ignore_errors' => true,
]])
);
$page = json_decode((string) $dataResponse, true, 64, JSON_THROW_ON_ERROR);

JavaScript — Node.js server

const clientId = process.env.STREAMERS_CLIENT_ID;
const clientSecret = process.env.STREAMERS_CLIENT_SECRET;

const tokenResponse = await fetch('https://streamers.cz/oauth2/token', {
method: 'POST',
headers: {'content-type': 'application/x-www-form-urlencoded'},
body: new URLSearchParams({
grant_type: 'client_credentials',
client_id: clientId,
client_secret: clientSecret,
scope: 'streamers:read'
})
});
if (!tokenResponse.ok) throw new Error('Token failed: ' + tokenResponse.status);
const token = await tokenResponse.json();

const response = await fetch('https://streamers.cz/api/streamers.php?limit=50&pagination=cursor', {
headers: {
authorization: 'Bearer ' + token.access_token,
'client-id': clientId
}
});
if (!response.ok) throw new Error('Data API failed: ' + response.status);
const page = await response.json();

Python

import json
import os
import urllib.parse
import urllib.request

client_id = os.environ["STREAMERS_CLIENT_ID"]
form = urllib.parse.urlencode({
"grant_type": "client_credentials",
"client_id": client_id,
"client_secret": os.environ["STREAMERS_CLIENT_SECRET"],
"scope": "streamers:read",
}).encode()

token_request = urllib.request.Request(
"https://streamers.cz/oauth2/token",
data=form,
headers={"Content-Type": "application/x-www-form-urlencoded"},
method="POST",
)
with urllib.request.urlopen(token_request, timeout=10) as response:
token = json.load(response)

data_request = urllib.request.Request(
"https://streamers.cz/api/streamers.php?limit=50&pagination=cursor",
headers={
"Authorization": f"Bearer {token['access_token']}",
"Client-Id": client_id,
},
)
with urllib.request.urlopen(data_request, timeout=10) as response:
page = json.load(response)

JavaScript ukázka je výhradně pro serverový runtime. Client Secret nesmí být součástí prohlížečového balíku, mobilní aplikace bez bezpečného backendu ani veřejného repozitáře.

Bezpečnost

Jak chránit aplikaci

  • Secret a access token ukládejte do serverového secret store nebo chráněných proměnných prostředí.
  • Neposílejte credentials v URL, cookies, alternativních hlavičkách ani logovacím kontextu.
  • Tokeny Streamers.cz nikdy nezaměňujte s uživatelským, administrátorským, Twitch nebo Kick OAuth.
  • Interní rozhraní, které používá samotný web Streamers.cz v prohlížeči, přenáší jen omezená data už veřejně zobrazená na webu. Není autentizační hranicí ani součástí podporovaného Data API kontraktu a Data API credentials nepřijímá.
  • Při úniku okamžitě otočte Client Secret; tím zneplatníte předchozí credential revision.
  • Validujte JSON a počítejte s volitelnými novými poli. Neznámé pole nemá rozbít klienta.
  • Respektujte viditelnost a podmínky dalšího zveřejnění dat. Scope není licence k vytváření neveřejné kopie služby.

Roadmapa

Co zatím není součástí API

Asynchronní exporty a podepsané webhooky nejsou v této chvíli veřejně dostupné. OpenAPI je proto neuvádí jako funkční endpointy.

Budoucí export bude vhodný pro větší dávky bez dlouhého HTTP requestu; webhook pro změny generací bez agresivního pollingu. Do zveřejnění použijte kurzorované čtení, cache na své straně a rozumný interval aktualizace.

Máte-li konkrétní serverový use case, napište přes Kontakt účel, rozsah, frekvenci a způsob dalšího použití. Neznamená to automatické zpřístupnění soukromých dat ani neomezeného exportu.