Go SDK Reference
Type reference for the PredictorSDK Go client.
The Go client is auto-generated from the OpenAPI spec and published as github.com/PredictorSDK/sdk-go.
Client surfaces
| Surface | Endpoint |
|---|---|
client.GetPlans(ctx) | GET /v1/plans (no auth required) |
client.GetSportsMatchingMarkets(ctx, request) | GET /v1/matching-markets/sports |
client.LookupSportsMatchingMarkets(ctx, request) | GET /v1/matching-markets/sports/lookup |
client.GetMarkets(ctx, request) | GET /v1/markets |
client.GetCategories(ctx) | GET /v1/categories |
client.GetMarket(ctx, request) | GET /v1/markets/{market_id} |
client.GetEvent(ctx, request) | GET /v1/events/{event_id} |
client.GetBinanceCryptoPrices(ctx, request) | GET /v1/crypto-prices/binance |
client.GetPolymarketWallet(ctx, request) | GET /v1/polymarket/wallet |
client.ListPolymarketWalletPositions(ctx, request) | GET /v1/polymarket/wallet/positions |
Four surfaces are paginated with a cursor: GetSportsMatchingMarkets, GetMarkets, GetBinanceCryptoPrices and ListPolymarketWalletPositions. Each returns a *core.Page that walks the cursor for you; see Pagination. The other surfaces return the parsed response.
Usage
import (
"context"
"fmt"
predictorsdk "github.com/PredictorSDK/sdk-go"
predictorclient "github.com/PredictorSDK/sdk-go/client"
"github.com/PredictorSDK/sdk-go/option"
)
func main() {
client := predictorclient.New(option.WithToken("YOUR_API_KEY"))
// A paginated call returns a page: page.Results holds this page's events.
page, err := client.GetSportsMatchingMarkets(context.TODO(), &predictorsdk.GetSportsMatchingMarketsRequest{
League: predictorsdk.GetSportsMatchingMarketsRequestLeagueNfl.Ptr(),
})
if err != nil {
panic(err)
}
for _, event := range page.Results {
fmt.Println(event.EventID, event.ScheduledDate.Format("2006-01-02"), event.Title)
}
// A lookup finds events by identifier and answers one unpaginated response.
found, err := client.LookupSportsMatchingMarkets(context.TODO(), &predictorsdk.LookupSportsMatchingMarketsRequest{
SourceID: []*string{predictorsdk.String("kalshi:KXNBAGAME-26OCT20OKCSAS")},
})
if err != nil {
panic(err)
}
fmt.Println(found.Lookups)
categories, _ := client.GetCategories(context.TODO())
plans, _ := client.GetPlans(context.TODO()) // Public: works without an API key.
fmt.Println(categories, plans)
}Pagination
A call to GetSportsMatchingMarkets, GetMarkets, GetBinanceCryptoPrices or ListPolymarketWalletPositions returns a *core.Page. Its iterator visits every item on every page; the client sends each next cursor and repeats the filters that issued it. Pass nil as the request to use every default.
import (
"errors"
"github.com/PredictorSDK/sdk-go/core"
)
// Every event on every page.
page, err := client.GetSportsMatchingMarkets(ctx, &predictorsdk.GetSportsMatchingMarketsRequest{
League: predictorsdk.GetSportsMatchingMarketsRequestLeagueNfl.Ptr(),
Limit: predictorsdk.Int(50),
})
if err != nil {
return err
}
iterator := page.Iterator()
for iterator.Next(ctx) {
event := iterator.Current()
fmt.Println(event.EventID, event.Title)
}
if err := iterator.Err(); err != nil {
return err
}
// 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.
markets, err := client.GetMarkets(ctx, &predictorsdk.GetMarketsRequest{
Provider: predictorsdk.GetMarketsRequestProviderProphetx.Ptr(),
Limit: predictorsdk.Int(100),
})
for err == nil {
fmt.Println(len(markets.Results), *markets.Response.Pagination.Total)
markets, err = markets.GetNextPage(ctx)
}
if !errors.Is(err, core.ErrNoPages) { // ErrNoPages marks the end, not a failure
return err
}| Member | Description |
|---|---|
page.Results | The items on the current page |
page.Response | The whole response of the current page, such as Snapshot and Pagination |
page.StatusCode, page.Header | The current page's HTTP metadata |
page.GetNextPage(ctx) | The next page, or core.ErrNoPages after the last one |
page.Iterator() | An iterator from this page on: Next(ctx), Current() and Err() |
Pagination.Total is a *int: set on GetMarkets and GetSportsMatchingMarkets, and nil on GetBinanceCryptoPrices and ListPolymarketWalletPositions, whose upstreams cannot count. Follow GetNextPage rather than Total. See the Pagination guide for the cursor rules.
Configuration
Options are passed to predictorclient.New():
| Option | Description |
|---|---|
option.WithToken(token) | Your API key (Bearer token) |
option.WithBaseURL(url) | Override the base URL |
option.WithHTTPClient(client) | Custom *http.Client. The default client sets no timeout, so set one here or give each request a context deadline. |
option.WithHTTPHeader(header) | Additional HTTP headers |
option.WithMaxAttempts(n) | Attempts for a 408, 429 or 5xx response or a connection that failed before any response, the first included (default: 3) |
option.WithoutRetries() | Send each request once |
Key types
All types live in the root predictorsdk package:
import predictorsdk "github.com/PredictorSDK/sdk-go"SportsMatchingListResponse
The Response of the page GetSportsMatchingMarkets returns.
| 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 set to true |
Pagination | *PaginationBlock | Pagination metadata |
Snapshot | *SportsMatchingSnapshot | Matching freshness. ObservedAt is when the oldest venue read behind the snapshot began, or nil 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 is false |
Lookups | map[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 | *time.Time | When the game starts, when a venue published an exact start time; nil when venues publish only a date. Millisecond precision, in UTC |
ScheduledDate | time.Time | The game's calendar day in America/New_York, as a date at midnight UTC: format it with Format("2006-01-02"). Always set, even when ScheduledStart is nil |
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 | int | Echoes the limit request param (default 25, max 100) |
Total | *int | Total matching items across all pages; nil on the routes that cannot count (wallet positions, crypto prices) |
HasMore | bool | true when more pages exist |
NextCursor | *string | 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 by converting it, predictorsdk.GetMarketRequestProvider(m.Provider).Ptr() (or GetEventRequestProvider for GetEvent), or use the composite string(m.Provider) + ":" + m.MarketID. Any of EventID, MarketID or MarketSlug, prefixed with Provider, finds the event again as SourceID; so does a Polymarket, Predict or AlphaArcade OutcomeID. 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 | 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 nil to list every matched event with defaults. The filters narrow the list, and Total, HasMore and the cursors describe the filtered set.
| Field | Type | Description |
|---|---|---|
Limit | *int | 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: GetSportsMatchingMarketsRequestLeagueNba, ...Wnba, ...Nfl, ...Mlb or ...Nhl, each with a Ptr() |
ScheduledDate | *time.Time | Only the games on this day in America/New_York, sent as YYYY-MM-DD: the event's ScheduledDate. Build one with predictorsdk.Time(predictorsdk.MustParseDate("2026-10-15")) |
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 | *bool | Also read the settled archive: games whose date has passed, and cancelled games (default false) |
IncludeSubmarkets | *bool | Every matched submarket, or only the full-game moneyline (default false) |
PlayerPropMatch | *GetSportsMatchingMarketsRequestPlayerPropMatch | Player-prop policy, e.g. predictorsdk.GetSportsMatchingMarketsRequestPlayerPropMatchSameProp.Ptr(); requires IncludeSubmarkets |
LookupSportsMatchingMarketsRequest
Send at least one identifier; with both, at most 100 unique values in all. EventID and SourceID take one *string per identifier, so a lookup is
SourceID: []*string{predictorsdk.String("kalshi:KXNBAGAME-26OCT20OKCSAS")}.
| Field | Type | Description |
|---|---|---|
EventID | []*string | Canonical event key(s) |
SourceID | []*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 | *bool | Also search the settled archive: games whose date has passed, and cancelled games (default false) |
IncludeSubmarkets | *bool | Every matched submarket (default true for a lookup), or only the full-game moneyline |
PlayerPropMatch | *LookupSportsMatchingMarketsRequestPlayerPropMatch | Player-prop policy; requires IncludeSubmarkets, the default for a lookup |
Lookups then reports what each identifier found:
for identifier, found := range response.Lookups {
fmt.Println(identifier, found.EventIDs)
}MarketsListResponse
The Response of the page GetMarkets returns. 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
Pass nil to fetch all markets with defaults, or provide pagination fields.
| Field | Type | Description |
|---|---|---|
Limit | *int | 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
GetMarketRequest.MarketID and GetEventRequest.EventID take an ID that is either platform-native or the composite {provider}:{id}. Both requests take an optional Provider (*GetMarketRequestProvider and *GetEventRequestProvider, such as predictorsdk.GetMarketRequestProviderKalshi.Ptr()) to say which venue an ID belongs to. A bare ID that more than one venue holds answers 409 as a *ConflictError listing the candidates; retry with Provider set to one of them, or with the composite form. The retired Platform is not accepted.
market, err := client.GetMarket(ctx, &predictorsdk.GetMarketRequest{
MarketID: "KXNBAGAME-26OCT20OKCSAS-OKC",
Provider: predictorsdk.GetMarketRequestProviderKalshi.Ptr(),
})
if err != nil {
return err
}
event, err := client.GetEvent(ctx, &predictorsdk.GetEventRequest{
EventID: "KXNBAGAME-26OCT20OKCSAS",
Provider: predictorsdk.GetEventRequestProviderKalshi.Ptr(),
})
if err != nil {
return err
}
// event.Provider is "kalshi": pass it back as Provider for the nested markets.
fmt.Println(market.ID, event.Provider)EventResponse
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 | 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 | *int64 | Start of the range, a Unix timestamp in milliseconds (inclusive) |
EndTime | *int64 | End of the range, a Unix timestamp in milliseconds (inclusive) |
Limit | *int | 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 Response of the page GetBinanceCryptoPrices returns: newest prices first, one per second.
| Field | Type | Description |
|---|---|---|
Data | []*CryptoPriceItem | The prices on this page |
Pagination | *PaginationBlock | Pagination metadata; Total is nil |
Pointer helpers
The predictorsdk package provides pointer helpers for building requests:
import predictorsdk "github.com/PredictorSDK/sdk-go"
request := &predictorsdk.LookupSportsMatchingMarketsRequest{
SourceID: []*string{predictorsdk.String("kalshi:KXNBAGAME-26OCT20OKCSAS")},
}Available helpers: String, Bool, Int, Int64, Float64, Time, UUID, and MustParseDate and MustParseDateTime to build a time.Time from a date or a timestamp string.
Raw responses
Use WithRawResponse on a surface that is not paginated to access HTTP metadata:
import (
"context"
"fmt"
predictorsdk "github.com/PredictorSDK/sdk-go"
predictorclient "github.com/PredictorSDK/sdk-go/client"
"github.com/PredictorSDK/sdk-go/option"
)
func main() {
client := predictorclient.New(option.WithToken("YOUR_API_KEY"))
raw, err := client.WithRawResponse.LookupSportsMatchingMarkets(context.TODO(), &predictorsdk.LookupSportsMatchingMarketsRequest{
SourceID: []*string{predictorsdk.String("kalshi:KXNBAGAME-26OCT20OKCSAS")},
})
if err != nil {
panic(err)
}
fmt.Println(raw.StatusCode)
fmt.Println(len(raw.Body.Data))
}A paginated surface keeps the metadata on its page: page.StatusCode and page.Header.
Error handling
The SDK returns typed errors for known HTTP error codes:
| Error type | 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 makes up to three attempts, the request and two retries, for a 408,
429 or 5xx response by default (option.WithMaxAttempts, which counts the
first attempt, or option.WithoutRetries). 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 the request's context ends a wait
as soon as it is done. 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 is retried the same way, with the same backoff and the same
limit. A timeout and a cancelled context are never retried. Every call is a
read, so repeating one is safe. The TypeScript and Python SDKs follow the same
policy, and core.APIError.Header carries the response's
request id.
import (
"context"
"errors"
"fmt"
predictorclient "github.com/PredictorSDK/sdk-go/client"
predictorsdk "github.com/PredictorSDK/sdk-go"
"github.com/PredictorSDK/sdk-go/option"
)
func main() {
client := predictorclient.New(option.WithToken("YOUR_API_KEY"))
// A venue ID needs its provider prefix: "kalshi:KXNBAGAME-26OCT20OKCSAS".
_, err := client.LookupSportsMatchingMarkets(context.TODO(), &predictorsdk.LookupSportsMatchingMarketsRequest{
SourceID: []*string{predictorsdk.String("KXNBAGAME-26OCT20OKCSAS")},
})
var badReq *predictorsdk.BadRequestError
if errors.As(err, &badReq) {
fmt.Println("Bad request:", badReq.Body.Code, badReq.Body.Message)
}
}