Mr. Doge

Reference

Matches

List, get, search, and subscribe to live matches across every major sport.

The matches resource is the workhorse of the SDK — every other resource hangs off it.

matches.list

Paginated list of matches matching the filters you pass.

const { data, pagination } = await mrdoge.matches.list({
  sports: ["soccer"],
  status: ["live"],
  limit: 20,
});

Params:

FieldTypeNotes
sportsstring[]"soccer", "basketball", "tennis", "volleyball", "baseball", "hockey", "football" (pass one or more)
competitionIdsnumber[]Filter to one or more competitions
regionIdsnumber[]Filter to one or more regions
teamIdsnumber[]Filter to matches involving any of the listed teams
statusMatchStatus[]["upcoming"], ["live"], ["completed"], or combinations
datestringYYYY-MM-DD — matches on this day
startDate / endDatestringRange filter
cursorstringPagination cursor (opaque)
limitnumberMax 100
selectMatchSelectField selector — see selectors
localestring"en", "pt-BR", "es"
timezonestringIANA timezone (e.g. "America/Sao_Paulo")

Returns: { data: Match[]; pagination: { nextCursor: string | null; hasMore: boolean } }

See pagination for the cursor walk.

matches.listAll

Auto-paginated version of matches.list. Walks all pages and returns the combined array.

const all = await mrdoge.matches.listAll(
  { sports: ["soccer"], status: ["live"] },
  {
    onPage: (page, accumulated) => render(accumulated),
    signal: controller.signal,
  },
);

Params: Same as matches.list minus cursor.

Options:

FieldTypeNotes
onPage(page, accumulated) => voidCalled per page for progressive rendering
signalAbortSignalCancel the walk mid-page

Returns: Match[] — every match across all pages.

matches.get

Single match by ID with full detail (MatchDetail).

const match = await mrdoge.matches.get({ id: "match_abc123" });

Params:

FieldTypeNotes
idstringMatch ID — strings, not numbers
selectMatchDetailSelectField selector
localestringLocalization

Returns: MatchDetail — includes stats, markets, and current clock.

matches.trending

Top matches by sport, server-prioritised.

const trending = await mrdoge.matches.trending({
  sports: ["soccer"],
  limit: 5,
});

Params:

FieldTypeNotes
sportsstring[]Optional — defaults to all sports
statusMatchStatus[]Optional
limitnumberMax 50, default 5
selectMatchSelectField selector

Returns: Match[]

matches.search

Free-text search across team names and competitions.

const results = await mrdoge.matches.search({
  query: "liverpool",
  limit: 10,
});

Params:

FieldTypeNotes
querystringMin 2 chars
sportsstring[]Optional — narrow by one or more sports
statusMatchStatus[]Optional
limitnumberMax 20
selectMatchSelectField selector

Returns: Match[]

matches.subscribeLive

Live-match subscription with WebSocket deltas. The killer feature.

const sub = await mrdoge.matches.subscribeLive({
  sports: ["soccer"],
});

// Initial state — already populated from the HTTP cold-start cache
console.log("Snapshot:", sub.snapshot.length, "matches");

// Stream deltas
sub.on("match.upd", (match) => render(match));
sub.on("match.del", (matchId) => removeFromUI(matchId));

// On any subscription closure (rate limit, auth expiry, server bounce, etc.)
sub.on("closed", ({ reason, message }) => {
  console.warn("Subscription closed:", reason, message);
});

// Tear down
await sub.cancel();

Params:

FieldTypeNotes
sportsstring[]Optional
regionIdsnumber[]Optional
competitionIdsnumber[]Optional
selectMatchSelectField selector — applies to snapshot AND every delta

Returns: Subscription<"matches.subscribeLive"> — see subscriptions.

Push events: match.upd (full match payload), match.del (matchId string)

The SDK races HTTP cache against WebSocket connect for the initial snapshot — sub.snapshot is populated in ~100ms instead of ~1.5s. Read the cold-start details →

matches.subscribe

Deep subscription for a single match — every odds change, stat update, and status transition.

const sub = await mrdoge.matches.subscribe({
  matchId: "match_abc123",
});

console.log("Match:", sub.snapshot);

sub.on("stats.upd", (stats) => updateScoreboard(stats));
sub.on("odds.upd", (markets) => repriceLines(markets));
sub.on("status.upd", ({ status }) => onPhaseChange(status));

Params:

FieldTypeNotes
matchIdstringRequired
selectMatchDetailSelectField selector — applies to snapshot, stats.upd, and odds.upd

Returns: Subscription<"matches.subscribe">

Push events: stats.upd (MatchStats), odds.upd (Market[]), status.upd ({ status })

matches.getLive

One-shot snapshot of all live matches matching the filters. No subscription, no deltas — useful for cron jobs or edge runtimes.

const snapshot = await mrdoge.matches.getLive({ sports: ["soccer"] });

Params:

FieldTypeNotes
sportsstring[]Optional
regionIdsnumber[]Optional
competitionIdsnumber[]Optional
selectMatchSelectField selector

Returns: Match[]

The Match shape

type Match = {
  id: string;                       // string, not number
  startTime: string;                // ISO 8601
  status: "upcoming" | "live" | "completed";
  homeTeam: { id: number; name: string };
  awayTeam: { id: number; name: string };
  sport: { id: number; name: string } | null;
  competition: { id: number; name: string };
  region: { id: number; name: string };
  markets: Market[];                // match-result + under/over odds
  stats?: MatchStats | null;        // only on completed matches in list responses
};

Use match.stats?.homeScore and match.stats?.awayScore for the score (when available). For live matches in subscribeLive snapshots, stats are included too.

Selectors

GraphQL-style projection — request only the fields you need. Reduces payload size, deserialization time, and re-render cost.

const { data } = await mrdoge.matches.list({
  sports: ["soccer"],
  select: {
    id: true,
    homeTeam: { name: true },
    awayTeam: { name: true },
    stats: { homeScore: true, awayScore: true, clock: { display: true } },
    // omit markets, competition, region, etc.
  },
});

Selectors apply to every match-bearing method:

  • matches.list, matches.get, matches.trending, matches.search, matches.getLive — applies to the response
  • matches.subscribeLive — applies to the initial snapshot AND every match.upd push for the lifetime of the subscription
  • matches.subscribe — same for stats.upd and odds.upd deltas

The select type (MatchSelect or MatchDetailSelect) walks the response shape recursively, so autocomplete drives every key. Selector rules:

  • field: true → include the full subtree
  • field: { …nested } → include only the listed nested fields
  • field omitted → not returned

Performance: projection is post-cache

The server caches the full response shape once, then projects per request. Two calls with different select shapes share the same upstream fetch and cache entry — you don't pay a cache miss for picking different fields.

This means feature-flag-driven selectors (e.g. one component renders homeScore, another renders homeScore + clock.display) are free — no extra round-trips.

Subscriptions: bandwidth savings compound

For long-lived subscribeLive subscriptions, the selector applies to every push. A subscription rendering 50 live matches with a 10-field selector instead of the full ~60-field default cuts your bandwidth and JSON-parse cost ~6×. The server stores the selector per-subscription and projects each delta before sending.

Next

On this page

Matches