Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.sportsxapp.com/llms.txt

Use this file to discover all available pages before exploring further.

STX.Sdk throws typed exceptions for every error condition you need to handle in application code. Network blips and transient HTTP failures are retried automatically via Polly before an exception ever reaches your code, so the exceptions you catch represent genuine problems that require action.

Exceptions

All STX-prefixed exceptions live in the STX.Sdk.Exceptions namespace.
ExceptionWhen thrownRecommended action
STXWrongCredentialsExceptionEmail or password rejected at loginPrompt the user for fresh credentials
STXTokenExpiredExceptionJWT expired; refresh token still validCall STXTokenService.RefreshTokenAsync
STXSessionExpiredExceptionBoth JWT and refresh token expiredCall STXLoginService.LoginAsync again
STXCancelOnDisconnectNotEnabledExceptionConfirmOrderAsync(cancelOnDisconnect: true) called before joining STXActiveOrdersChannelJoin the channel first, or set cancelOnDisconnect: false
STXGeoComplyExceptionGeo-compliance check failedUser is outside a permitted jurisdiction — surface to your UI
GraphQLHttpRequestExceptionNon-200 HTTP response after all retries exhaustedTreat as a service outage; back off and retry later

Handle authentication failures

try
{
    await login.LoginAsync(email, password);
}
catch (STXWrongCredentialsException)
{
    // Surface to UI: "Email or password is incorrect."
}
catch (STXGeoComplyException ex)
{
    // Surface to UI: "Trading isn't available in your region."
    _logger.LogWarning(ex, "Geo block on login");
}

Handle session expiry in trading calls

If you are not using keepSessionAlive: true, wrap trading calls with a token-refresh retry to handle expiry gracefully:
async Task<T> WithSession<T>(Func<Task<T>> call)
{
    try
    {
        return await call();
    }
    catch (STXTokenExpiredException)
    {
        // Refresh token is still valid — exchange it for a new JWT
        await _tokens.RefreshTokenAsync();
        return await call();
    }
    catch (STXSessionExpiredException)
    {
        // Both tokens expired — full re-login required
        await _login.LoginAsync(_email, _password);
        return await call();
    }
}

var order = await WithSession(() =>
    _orders.ConfirmOrderAsync(price, qty, marketId, action, orderType));
Using keepSessionAlive: true at login eliminates the need for this wrapper in long-running bots. STXSessionBackgroundService handles refresh automatically in the background.

Automatic transient retries

Every GraphQL mutation runs through STXGraphQLBaseService.SendMutationWithRetry, which uses Polly with the following default policy:
  • Retry triggers: HttpRequestException, TaskCanceledException (timeout), and 5xx responses.
  • Attempts: 3 retries after the initial failure (4 total).
  • Backoff: exponential — 200 ms, 400 ms, 800 ms.
You do not need to add your own retry around SDK calls. Doing so can amplify brief outages by turning a single transient failure into multiple redundant requests. If the error persists after all built-in retries, a GraphQLHttpRequestException surfaces. Treat it as a service outage — back off and try again after a delay.

Rate limits

The exchange rate-limits by IP and account. Bursty order placement can produce HTTP 429 responses.
The SDK does not retry 429 responses automatically. Retrying a 429 makes the situation worse. If you see them, reduce your request rate or consolidate orders with ConfirmOrdersAsync.

Debug logging

Enable Debug-level logging to inspect full GraphQL request and response bodies, including operation names, variables, and elapsed time. This is usually enough to determine whether an error is a transient network issue or a schema mismatch:
services.AddLogging(builder =>
    builder
        .SetMinimumLevel(LogLevel.Debug)
        .AddConsole());

See also