Go SDK
Typed responses and context-aware calls, errors you match with errors.Is, iterators for paged endpoints and a WebSocket client.
Install
One package, no setup beyond your API key.
$ go get github.com/sportsapiapp/sportsapi-goAuthenticate
Use the API key from your dashboard. Pass it to the client, or set SPORTSAPI_API_KEY and the client reads it.
client := sportsapi.NewClient(sportsapi.WithAPIKey("sk_live_…")) // or SPORTSAPI_API_KEYFirst calls
Every method returns the API's { data, meta } envelope, typed. Path parameters come first, in path order, then the query parameters with the API's own names.
live, err := client.Livescores.List(ctx, &sportsapi.LivescoresListParams{Sport: sportsapi.Ptr("football")}) if err != nil { log.Fatal(err) } for _, f := range live.Data { fmt.Println(f.Home.Name, *f.HomeScore.Current, "-", *f.AwayScore.Current, f.Away.Name) } table, err := client.Leagues.Standings(ctx, 17, &sportsapi.LeaguesStandingsParams{Season: 61627})
Errors
One error type per HTTP status, each carrying the API's code, message and Retry-After. Branch on the code, never on the message.
_, err := client.Fixtures.WinProbability(ctx, 211521, nil) switch { case errors.Is(err, sportsapi.ErrForbidden): // 403: endpoint_not_in_plan, … case errors.Is(err, sportsapi.ErrNotFound): // 404: not_found, no_data, not_supported } var apiErr *sportsapi.APIError if errors.As(err, &apiErr) { fmt.Println(apiErr.Status, apiErr.Code, apiErr.RetryAfter) }
Paging
Every endpoint with a page parameter has a pages iterator that walks the pages until there are no more.
for page, err := range client.Teams.FixturesPages(ctx, 42, &sportsapi.TeamsFixturesParams{Type: sportsapi.Ptr("recent")}) { if err != nil { log.Fatal(err) } fmt.Println(len(page.Data)) }
WebSocket stream (Business)
The stream mints its own single-use ticket, subscribes, reconnects and replays what it missed, and merges every delta into the fixtures it holds.
s, err := client.Stream(ctx, []string{"livescores", "fixture:237609"}, nil) if err != nil { log.Fatal(err) } defer s.Close() for f := range s.Frames() { if d, ok := f.Value.(*sportsapi.WsDelta); ok { fmt.Println("delta", d.ID) } live, _ := s.Fixtures("livescores") // the merged state, any time _ = live }
Options
A 429 rate_limited or a 503 is retried after Retry-After (twice by default); a quota error never is.
client := sportsapi.NewClient( sportsapi.WithAPIKey(key), // or SPORTSAPI_API_KEY sportsapi.WithMaxRetries(2), ) // SPORTSAPI_BASE_URL points it elsewhere