go-itchio is a set of Go bindings to interact with the itch.io API
For static API keys (CI environments, scripts, legacy integrations):
client := itchio.ClientWithKey("your-api-key")
// Use the client
games, err := client.ListProfileGames(ctx)For user-facing applications with automatic token refresh:
// Create an unauthenticated client for the initial exchange
client := itchio.ClientWithKey("")
// Exchange the authorization code for credentials
resp, err := client.ExchangeOAuthCode(ctx, itchio.ExchangeOAuthCodeParams{
Code: authCode,
CodeVerifier: verifier,
RedirectURI: redirectURI,
ClientID: "your-client-id",
})
// Create an OAuth client with automatic token refresh
client = itchio.NewOAuthClient(
resp.OAuthCredentials(),
itchio.OAuthConfig{
ClientID: "your-client-id",
OnRefresh: func(creds *itchio.OAuthCredentials) error {
// Persist refreshed credentials to your storage
return saveCredentials(creds)
},
},
)
// Use normally - tokens refresh automatically
games, err := client.ListProfileGames(ctx)The OAuth client automatically refreshes tokens before they expire and retries requests on 401 responses.
The itch.io API returns JSON with snake_case keys, but Go response types in this package use camelCase json struct tags (e.g. json:"coverUrl", not json:"cover_url"). Decoding happens in two steps:
- The response body is decoded into a generic
map[string]interface{}. - Every key in that map is recursively rewritten from
snake_casetocamelCasebycamelifyMap(seecamelify.go), thenmapstructurepopulates the target struct using thejsontag.
When defining new response types, write json tags in camelCase to match the post-remap keys.
The remap walks into nested maps and arrays by default, which would also rewrite the keys of arbitrary HTTP header maps returned by the API. To preserve those headers verbatim, upload_headers is listed in camelifyBlacklist (camelify.go): the field name itself is still camelified to uploadHeaders, but its inner map keys are left untouched. Add to this blacklist if you introduce another field whose values are user-controlled key/value data rather than a known schema.
Set GO_ITCHIO_DEBUG to enable request logging:
# Log all HTTP requests (method, URL, rate limiting)
GO_ITCHIO_DEBUG=1 ./your-app
# Also dump full API response bodies
GO_ITCHIO_DEBUG=2 ./your-appYou can attach a slog logger to emit structured per-attempt HTTP logs. These logs are emitted at DEBUG level:
logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
Level: slog.LevelDebug,
}))
client := itchio.ClientWithKey("your-api-key")
client.Logger = loggerEach log entry includes fields like method, url (with sensitive query values redacted), status_code, duration_ms, attempt, retrying, and retry_reason.
Licensed under MIT License, see LICENSE for details.