TypeScript SDK Reference
Type reference for the PredictorSDK TypeScript client.
The TypeScript client is auto-generated from the OpenAPI spec and published as @predictorsdk/client on npm. It needs Node 18 or later and works with both import and require: the package ships an ES module build and a CommonJS build, each with its own types.
// CommonJS
const { PredictorSDKClient } = require("@predictorsdk/client");An app that loads the package both ways gets two copies of it, so an error thrown by one is not an instanceof the other's PredictorSDKError; use one style.
Client surfaces
| Surface | Endpoint |
|---|---|
client.getPlans() | GET /v1/plans (no auth required) |
client.getSportsMatchingMarkets(request) | GET /v1/matching-markets/sports |
client.lookupSportsMatchingMarkets(request) | GET /v1/matching-markets/sports/lookup |
client.getMarkets(request) | GET /v1/markets |
client.getCategories() | GET /v1/categories |
client.getMarket(request) | GET /v1/markets/{market_id} |
client.getEvent(request) | GET /v1/events/{event_id} |
client.getBinanceCryptoPrices(request) | GET /v1/crypto-prices/binance |
client.getPolymarketWallet(request) | GET /v1/polymarket/wallet |
client.listPolymarketWalletPositions(request) | GET /v1/polymarket/wallet/positions |
When you await a call to one of the other surfaces, it resolves to the parsed response body. Use .withRawResponse() if you also need headers or status metadata.
Four surfaces are paginated with a cursor: getSportsMatchingMarkets, getMarkets, getBinanceCryptoPrices and listPolymarketWalletPositions. Each resolves to a Page that walks the cursor for you; see Pagination.
Usage
import { PredictorSDKClient } from "@predictorsdk/client";
const client = new PredictorSDKClient({
token: "YOUR_API_KEY",
});
// A paginated call answers a page: page.data holds this page's events.
const page = await client.getSportsMatchingMarkets({ league: "nfl" });
for (const event of page.data) {
console.log(event.eventId, event.scheduledDate, event.scheduledStart, event.title);
}
// A lookup finds events by identifier and answers one unpaginated response.
const found = await client.lookupSportsMatchingMarkets({
sourceId: "kalshi:KXNBAGAME-26OCT20OKCSAS",
});
const categories = await client.getCategories();
const plans = await client.getPlans(); // Public; no API key is sent.Pagination
A call to getSportsMatchingMarkets, getMarkets, getBinanceCryptoPrices or listPolymarketWalletPositions resolves to a Page. Iterate it with for await to visit every item on every page; the client sends each next cursor and repeats the filters that issued it.
// Every event on every page.
const page = await client.getSportsMatchingMarkets({ league: "nfl", limit: 50 });
for await (const event of page) {
console.log(event.eventId, event.title);
}
// One provider's markets, a page at a time. The whole catalog is about
// 470,000 markets, thousands of pages, so filter by provider or category first.
const markets = await client.getMarkets({ provider: "prophetx", limit: 100 });
while (true) {
console.log(markets.data.length, markets.response.pagination.total);
if (!markets.hasNextPage()) break;
await markets.getNextPage(); // advances `markets` in place
}| Member | Description |
|---|---|
page.data | The items on the current page |
page.response | The whole response body of the current page, such as snapshot and pagination |
page.rawResponse | The current page's HTTP metadata: status and headers |
page.hasNextPage() | true while pagination.nextCursor is set |
page.getNextPage() | Fetches the next page, moves page onto it and returns it |
for await (const item of page) | Visits page.data, then every later page |
Iterating or calling getNextPage() moves the same Page forward, so read page.response first if you need the first page's pagination or snapshot. pagination.total is a number on getMarkets and getSportsMatchingMarkets, and null on getBinanceCryptoPrices and listPolymarketWalletPositions, whose upstreams cannot count; follow hasNextPage() rather than total. See the Pagination guide for the cursor rules.
Configuration
| Option | Type | Description |
|---|---|---|
token | string | Your API key (Bearer token) |
baseUrl | string | Override the base URL |
environment | PredictorSDKEnvironment | API environment (defaults to Production) |
timeoutInSeconds | number | Request timeout in seconds (default: 60) |
maxRetries | number | Retries after a 408, 429 or 5xx response, or a connection that failed before any response (default: 2) |
fetch | typeof fetch | Custom fetch implementation |
Key types
SportsMatchingListResponse
The page.response of getSportsMatchingMarkets. Contains the matched events in data, the pagination block, and a snapshot freshness block.
| Field | Type | Description |
|---|---|---|
data | CanonicalSportsEvent[] | Matched events, soonest scheduled start first, each once. Each carries its full-game moneyline, or every matched submarket with includeSubmarkets: true |
pagination | PaginationBlock | Pagination metadata |
snapshot | SportsMatchingSnapshot | Matching freshness. observedAt is when the oldest venue read behind the snapshot began, or null when unknown — check it before treating a missing event as unmatched |
SportsMatchingLookupResponse
The response from lookupSportsMatchingMarkets: one unpaginated response, with no pagination block.
| Field | Type | Description |
|---|---|---|
data | CanonicalSportsEvent[] | The events the identifiers found, soonest scheduled start first, each once, with every matched submarket unless includeSubmarkets: false |
lookups | Record<string, SportsMatchingLookupResult> | Every eventId and sourceId you sent, as sent, with the events it found |
snapshot | SportsMatchingSnapshot | Matching freshness, as above |
SportsMatchingLookupResult
| Field | Type | Description |
|---|---|---|
eventIds | string[] | The eventIds of the events in data that hold the identifier; empty when it found none |
CanonicalSportsEvent
One matched game, as the list and the lookup both return it.
| Field | Type | Description |
|---|---|---|
eventId | string | The canonical event key, such as nba-okc-sas-2026-10-20 |
sport | string | The sport, such as basketball |
league | string | The league: nba, wnba, nfl, mlb or nhl |
title | string | The event title, such as Oklahoma City Thunder vs. San Antonio Spurs |
scheduledStart | Date | null | When the game starts, when a venue published an exact start time; null when venues publish only a date. Millisecond precision, in UTC |
scheduledDate | string | The game's calendar day in America/New_York, as YYYY-MM-DD. Always present, even when scheduledStart is null |
participants | CanonicalSportsParticipant[] | The two sides, each with a key, a name and a role (away or home) |
submarkets | CanonicalSportsSubmarket[] | The matched submarkets in reading order: the full game, then each half and quarter, and within each the moneyline, spreads, totals, team totals and props |
PaginationBlock
| Field | Type | Description |
|---|---|---|
limit | number | Echoes the limit request param (default 25, max 100) |
total | number | null | Total matching items across all pages; null on the routes that cannot count (wallet positions, crypto prices) |
hasMore | boolean | true when more pages exist |
nextCursor | string | undefined | The cursor for the next page. A Page sends it for you; pass it back as cursor only to resume a walk by hand |
CanonicalSportsSourceMarket
One venue market matched to a canonical submarket, with the same fields on every venue. eventId is the venue's parent event, for getEvent; marketId is the market itself, for getMarket. Pass provider to either call as its provider, or use the composite provider + ":" + id. Any of eventId, marketId or marketSlug, prefixed with provider, finds the event again as sourceId. See Which identifier goes where.
| Field | Type | Description |
|---|---|---|
provider | CanonicalSportsSourceMarketProvider | kalshi, polymarket, predict, sxbet, alpha-arcade, prophetx, pred, or limitless |
eventId | string | The venue's parent event, for getEvent. Not a market ID |
marketId | string | The market, for getMarket. Kalshi lists a game winner as one market per team, so it appears once per team |
marketName | string | The market's name: the venue's own title, or on SX Bet its two outcome labels, as getMarket titles it |
marketSlug | string | undefined | The venue's slug, where it has one (Polymarket, AlphaArcade). sourceId accepts it; for getMarket send marketId |
outcomes | CanonicalSportsSourceOutcome[] | Each side's outcomeId and label, mapped to a canonical outcome; getMarket returns the same IDs. Kalshi and Pred sides are yes/no, labelled Yes/No |
GetSportsMatchingMarketsRequest
Pass an empty object {} (or nothing) to list every matched event. The filters narrow the list, and total, hasMore and the cursors describe the filtered set.
| Field | Type | Description |
|---|---|---|
limit | number | Events per page (1–100, default 25) |
cursor | string | Resumes a walk by hand; a Page sends it for you. Valid only with the filters that issued it |
league | GetSportsMatchingMarketsRequestLeague | Only this league: nba, wnba, nfl, mlb or nhl |
scheduledDate | string | Only the games on this day, as YYYY-MM-DD in America/New_York: the event's scheduledDate |
participant | string | Only events with a participant whose key is this (such as okc), case-insensitive. Keys are unique only within a league (la is the Rams in the NFL and the Sparks in the WNBA), so pair it with league |
includeSettled | boolean | Also read the settled archive: games whose date has passed, and cancelled games (default false) |
includeSubmarkets | boolean | Every matched submarket, or only the full-game moneyline (default false) |
playerPropMatch | strict | same_prop | Player-prop policy; requires includeSubmarkets: true (default strict) |
// Tonight's NFL games: filters compose, and every page keeps them.
const page = await client.getSportsMatchingMarkets({
league: "nfl",
scheduledDate: "2026-10-15",
});
for await (const event of page) {
console.log(event.eventId, event.scheduledStart);
}LookupSportsMatchingMarketsRequest
Send at least one identifier; with both parameters, at most 100 unique values in all.
| Field | Type | Description |
|---|---|---|
eventId | string | string[] | Canonical event key(s) |
sourceId | string | string[] | Venue ID(s) as {provider}:{id}: any marketId, marketSlug or eventId a source market publishes, a Polymarket, Predict or AlphaArcade outcome token, or a Polymarket condition ID. Case-insensitive |
includeSettled | boolean | Also search the settled archive: games whose date has passed, and cancelled games (default false) |
includeSubmarkets | boolean | Every matched submarket (default true for a lookup), or only the full-game moneyline |
playerPropMatch | strict | same_prop | Player-prop policy; requires includeSubmarkets: true, the default for a lookup (default strict) |
// `lookups` reports what each identifier found; there is no pagination block.
const response = await client.lookupSportsMatchingMarkets({
sourceId: ["kalshi:KXNBAGAME-26OCT20OKCSAS", "sxbet:L19766755"],
});
for (const [id, found] of Object.entries(response.lookups)) {
console.log(id, found.eventIds);
}MarketsListResponse
The page.response of getMarkets. Contains data, catalog snapshot freshness, and pagination.
| Field | Type | Description |
|---|---|---|
data | UnifiedMarket[] | Array of markets for the current page |
snapshot | MarketsSnapshot | Catalog freshness; observedAt is when the crawl behind the oldest provider snapshot in the bound page scope began |
pagination | PaginationBlock | Pagination metadata |
UnifiedMarket
A market from any supported prediction market provider.
| Field | Type | Description |
|---|---|---|
id | string | Composite ID in the format {provider}:{provider_id} |
provider | UnifiedMarketProvider | kalshi, polymarket, predict, sxbet, hyperliquid, alpha-arcade, prophetx, limitless, or pred |
title | string | Human-readable market title/question |
category | MarketCategory | Canonical top-level category, such as sports, politics, or crypto |
GetMarketsRequest
| Field | Type | Description |
|---|---|---|
limit | number | Results per page (1–100, default 25) |
cursor | string | Resumes a walk by hand; a Page sends it for you |
category | MarketCategory | Optional canonical category filter |
provider | GetMarketsRequestProvider | Optional canonical provider filter; replay cursors with the same value |
GetMarketRequest and GetEventRequest
getMarket takes a marketId and getEvent an eventId, either as a platform-native ID or the composite {provider}:{id}. Both take an optional provider (GetMarketRequestProvider and GetEventRequestProvider) to say which venue an ID belongs to. A bare ID that more than one venue holds answers 409 with the candidates; retry with provider set to one of them, or with the composite form. The retired platform is not accepted.
const market = await client.getMarket({
marketId: "KXNBAGAME-26OCT20OKCSAS-OKC",
provider: "kalshi",
});
const event = await client.getEvent({ eventId: "KXNBAGAME-26OCT20OKCSAS", provider: "kalshi" });
console.log(event.provider); // "kalshi": pass it back as `provider` for the nested marketsEventResponse
The response from getEvent.
| Field | Type | Description |
|---|---|---|
eventId | string | Echo of the event ID you sent |
provider | EventResponseProvider | The venue the ID resolved against, the value to pass as provider to getMarket for its nested markets |
title | string | The event title |
markets | EventMarket[] | The markets nested under the event, each with a platform-native marketId and a title |
fanout | EventFanout | undefined | Present when Kalshi sibling events were merged in; lists which siblings were attempted and which returned nothing |
GetBinanceCryptoPricesRequest
| Field | Type | Description |
|---|---|---|
currency | string | Binance trading pair, such as btcusdt |
startTime | number | Start of the range, a Unix timestamp in milliseconds (inclusive) |
endTime | number | End of the range, a Unix timestamp in milliseconds (inclusive) |
limit | number | Prices per page, 1–100 (default 100 with a time range); more than 100 is a 400 |
cursor | string | Resumes a walk by hand; a Page sends it for you. The retired paginationKey is not accepted |
CryptoPricesResponse
The page.response of getBinanceCryptoPrices: newest prices first, one per second.
| Field | Type | Description |
|---|---|---|
data | CryptoPriceItem[] | The prices on this page |
pagination | PaginationBlock | Pagination metadata; total is null |
Raw responses
Use .withRawResponse() on a surface that is not paginated to access HTTP metadata alongside the parsed body:
const raw = await client
.lookupSportsMatchingMarkets({ sourceId: "kalshi:KXNBAGAME-26OCT20OKCSAS" })
.withRawResponse();
console.log(raw.rawResponse.status);
console.log(raw.rawResponse.headers.get("X-RateLimit-Reset")); // Unix seconds
console.log(raw.data.data.length);A paginated surface keeps the metadata on its page:
const page = await client.getSportsMatchingMarkets();
console.log(page.rawResponse.status);
console.log(page.rawResponse.headers.get("X-RateLimit-Reset")); // Unix secondsError handling
The SDK throws typed errors for known HTTP error codes:
| Error class | Status code | Description |
|---|---|---|
BadRequestError | 400 | Invalid query parameters |
UnauthorizedError | 401 | Missing or invalid API key |
PaymentRequiredError | 402 | Monthly allowance exhausted or subscription payment recovery required |
ForbiddenError | 403 | Insufficient permissions |
NotFoundError | 404 | Market or event not found |
ConflictError | 409 | Bare identifier resolves on multiple providers; retry with provider or a composite ID |
TooManyRequestsError | 429 | Rate limit exceeded |
BadGatewayError | 502 | Upstream provider or API-key authorization dependency failure |
ServiceUnavailableError | 503 | Service temporarily unavailable |
The client retries a 408, 429 or 5xx response twice by default
(maxRetries, on the client or per request). A 429 waits for Retry-After,
or else until the second-based X-RateLimit-Reset. Any other retried status
honours Retry-After and otherwise backs off exponentially from one second. No
wait exceeds 60 seconds, and an abortSignal ends a wait as soon as it aborts;
timeoutInSeconds limits each attempt. A 409 is never retried: send the
request again with a provider from its candidates.
A request that gets no response because the connection was refused, reset or
closed by the server (Node reports ECONNREFUSED, ECONNRESET or
UND_ERR_SOCKET on the error's cause) is retried the same way, with the same
backoff and the same limit. A timeout and an abort are never retried. Every call
is a read, so repeating one is safe. The Go and Python SDKs follow the same
policy, and error.requestId is the response's
request id.
import { PredictorSDK, PredictorSDKClient } from "@predictorsdk/client";
const client = new PredictorSDKClient({
token: "YOUR_API_KEY",
});
try {
// A venue ID needs its provider prefix: "kalshi:KXNBAGAME-26OCT20OKCSAS".
await client.lookupSportsMatchingMarkets({ sourceId: "KXNBAGAME-26OCT20OKCSAS" });
} catch (error) {
if (error instanceof PredictorSDK.BadRequestError) {
console.log("Bad request:", error.body.code, error.body.message);
}
}