Developer resources

StreamCenter API

Streams API

Resolve all currently usable streams in one provider group. Source names are opaque, operator-defined values: always obtain them from a match response rather than inventing or hard-coding them.

Base URL: https://streamcenter.st

Stream structure

TypeScript
interface APIStream {
  id: string;
  streamNo: number;
  language: string;
  hd: boolean;
  embedUrl: string;
  webUrl?: string;
  source: string;
}
Resolved stream fields
FieldTypeDescription
idstringIndividual stored stream-row ID.
streamNonumberStable stream number within its source.
languagestringHuman-readable English language name.
hdbooleanWhether the source is marked high definition.
embedUrlstringCurrent validated HTTPS embed URL.
webUrlstringCanonical StreamCenter Watch-page URL for the complete match.
sourcestringProvider/source requested in the route.

Endpoint and flow

GET /api/stream/{source}/{matchId}

  1. Fetch a match selection.
  2. Choose one object from match.sources.
  3. Put its source and id into this route.
Shell
curl --fail-with-body --silent --show-error \
  "https://streamcenter.st/api/stream/example-source/match-123"
JavaScript
const matchesResponse = await fetch("https://streamcenter.st/api/matches/live");
if (!matchesResponse.ok) throw new Error("Could not load matches");
const matches = await matchesResponse.json();
if (!Array.isArray(matches) || matches.length === 0) {
  throw new Error("No live match is available");
}

const match = matches[0];
const group = match.sources[0];

const streamsResponse = await fetch(
  `https://streamcenter.st/api/stream/${encodeURIComponent(group.source)}/${encodeURIComponent(group.id)}`
);
if (!streamsResponse.ok) {
  const requestId = streamsResponse.headers.get("X-Request-ID");
  throw new Error(`Stream request failed (reference: ${requestId ?? "unknown"})`);
}

const streams = await streamsResponse.json();
if (!Array.isArray(streams)) throw new Error("Invalid stream response");
if (streams.length === 0) throw new Error("No stream survived validation");
for (const stream of streams) {
  console.log(
    stream.language,
    stream.hd ? "HD" : "SD",
    "Watch:",
    stream.webUrl,
    "Embed:",
    stream.embedUrl
  );
}

Example response

JSON
[
  {
    "id": "stream-english",
    "streamNo": 1,
    "language": "English",
    "hd": true,
    "embedUrl": "https://player.example/english",
    "webUrl": "https://streamcenter.st/watch/match-123",
    "source": "example-source"
  },
  {
    "id": "stream-spanish",
    "streamNo": 2,
    "language": "Spanish",
    "hd": false,
    "embedUrl": "https://player.example/spanish",
    "webUrl": "https://streamcenter.st/watch/match-123",
    "source": "example-source"
  }
]

Embed a selected stream

Navigate to webUrl for the complete StreamCenter Watch page. To embed only the selected third-party player, use a descriptive title, grant only the required capabilities, avoid leaking the parent-page referrer, and keep the API-returned embedUrl.

HTML
<iframe
  src="https://player.example/english"
  title="North City vs. South United — English stream"
  allow="autoplay *; encrypted-media *; fullscreen *; picture-in-picture *"
  referrerpolicy="no-referrer"
  allowfullscreen
></iframe>

Failures and partial groups

  • An unavailable or unauthorized group returns 404.
  • If one member fails validation but another succeeds, the response contains only valid members.
  • The limit is 60 requests per minute per client IP. A 429 includes Retry-After.
  • Treat network errors as temporary and retain the request reference from X-Request-ID when a response exists.

Need group IDs? Begin with the Matches API.