Skip to content

Error Reference

All API errors return an applicable HTTP status code (400-level or 500-level) along with the following JSON body:

json
{
  "success": false,
  "error": "Human-readable error description"
}

TLDR

CodeMeaningYour Action
200SuccessUse the data
400Bad RequestFix parameters - check validation errors
401UnauthorizedCheck API key header/parameter
403ForbiddenCheck subscription status or feature access
404Not FoundVerify endpoint path
429Rate LimitedWait and then retry. Upgrade subscriptionif persistent
500Server ErrorRetry once after delay, simplify query if persistent
503Service UnavailableWait for service to reconnect
504Gateway TimeoutReduce query complexity, retry once after delay

Types of Errors

Non-Standard Response Format

In rare cases you may receive:

  • An empty response body
  • A non-JSON response body (ex: text or html)
  • A response body which isn’t parseable into JSON
  • A response body without a success field

Meaning: These are typically due to transient networking issues or server errors.

Recommendation:

  • Treat these the same as a 500-level error.
  • Retry the request once after a short delay
  • If you see these repeatedly and the request still fails after a retry, please contact support.

400 Bad Request

Meaning: Your request has invalid or missing parameters.

Troubleshooting:

  • Typically the error field in the response will be helpful to determine what the issue is
  • Check the reference docs and the data-types docs to help ensure you’re using the correct values.
  • Make sure you haven’t included the same parameter multiple times.
  • If it’s a boolean parameter, make sure it’s either true or false (as a string)
  • If it’s a date parameter, make sure it’s a valid ISO-formatted date or Unix timestamp. Ex: 2026-01-01T00:00:00.000Z or 1736899200000
  • In some cases, you may be using an invalid combination of parameters. These are combinations of query parameters which can’t logically go together such as live=true with ended=true.

401 Unauthorized

Meaning: Authentication failed or API key is missing.

Troubleshooting:

  • Make sure you’ve included your API key either in the header as x-api-key (case-insensitive) or as a query parameter as apiKey.
  • Ensure that the API key doesn’t contain any leading or trailing whitespace.
  • Make sure you copied your API key correctly. Check your email and ensure you’re using the same key which was sent to you.
  • Make sure your API key hasn’t been re-generated or revoked.

403 Forbidden

Meaning: Your API key doesn’t have permission to access this data

Troubleshooting:

  • Make sure you haven’t cancelled your subscription. Check your subscription here.
  • If you’re on a paid plan, make sure you didn’t have a failed payment/billing issue
  • Make sure you’re using the latest API version. By default API keys are not granted access to old/legacy API versions.
  • Certain endpoints may be restricted by tier. For example, the /stream/events endpoint is only available on the AllStar plan. Contact support to upgrade.

404 Not Found

Meaning: The requested resource doesn’t exist.

Troubleshooting:

  • Make sure you’re using the correct URL to query the API. Check for typos.
  • The version of your API request was invalid. Make sure your URL path starts with /v2/ or /v1/ or another valid version.

429 Too Many Requests

Meaning: You’ve exceeded your rate limits

Troubleshooting:

  • Try waiting up to a minute and then try again
  • Check your rate limit usage using the /account/usage endpoint
  • If you ran out of “objects per month” then you may need to upgrade your plan

500 Internal Server Error

Meaning: Something went wrong on our end.

Troubleshooting:

  • Wait a few seconds and then retry the request once.
  • If it still fails, then contact support
  • Consider trying a different endpoint or different set of query parameters. Sometimes active problems are isolated to only specific cases of these
  • In general, these errors are not your fault and should be exceedingly rare
  • We ask that you do not continuously retry the request as this tends to overload our servers and may result in additional errors

503 Service Unavailable

Meaning: API is temporarily unavailable or our server is offline

Troubleshooting:

  • Wait a few seconds and then retry the request once.
  • If it still fails, then contact support
  • In some cases, these types of errors are isolated to a single server instance. If that’s what’s happening, your retry may work. Otherwise, it’s likely a more widespread issue with our servers.

504 Gateway Timeout

Meaning: Request took too long to complete.

Troubleshooting:

  • Your query may be too complex. The following can help reduce query complexity:
    • Remove these parameters: includeAltLines, startsBefore, startsAfter, playerID/playerIDs, bookmakerID/bookmakerIDs, teamID/teamIDs
    • Reduce the overall number of query parameters you’re using
  • Our servers may be overloaded. Wait a few seconds and then retry the request once.
  • If it still fails, then contact support

Error Handling Example

js
async function fetchSGO(url, options = {}, canRetry = true) {
  let response, payload, error;
  try {
    response = await fetch(url, options);
    payload = await response.json();
  } catch (e) {
    error = e;
  }

  const success = payload?.success;
  const status = response?.status;
  if (success === true) return payload.data;

  const isClientError = success === false && status >= 400 && status < 500 && status !== 429;
  if (canRetry && !isClientError) {
    const backoffMs = 2000 + Math.floor(Math.random() * 3000);
    await new Promise((resolve) => setTimeout(resolve, backoffMs));
    return fetchSGO(url, options, false);
  }

  console.error(`SGO Request Failed: ${status} ${payload?.error || error?.message}`, { url, options, payload, error });
  return null;
}
python
import requests
import random
import time

def fetch_sgo(url, options=None, can_retry=True):
    options = options or {}
    response = None
    payload = None

    try:
        response = requests.request(
            method=options.get('method', 'GET'),
            url=url,
            headers=options.get('headers'),
            json=options.get('body')
        )
        payload = response.json()
    except Exception as e:
        error = e
    else:
        error = None

    if payload and payload.get('success') is True:
        return payload.get('data')

    status = response.status_code if response else None
    is_client_error = (
        payload and payload.get('success') is False
        and status and 400 <= status < 500 and status != 429
    )

    if can_retry and not is_client_error:
        time.sleep(2 + random.random() * 3)
        return fetch_sgo(url, options, can_retry=False)

    error_msg = (payload or {}).get('error') or (str(error) if error else 'Unknown')
    print(f"SGO Request Failed: {status} {error_msg}")
    return None
java
import java.net.URI;
import java.net.http.*;
import java.time.Duration;
import java.util.Map;
import java.util.Random;
import com.google.gson.*;

public class SgoClient {
    private static final HttpClient client = HttpClient.newHttpClient();
    private static final Gson gson = new Gson();
    private static final Random random = new Random();

    public static JsonElement fetchSgo(String url, Map<String, String> headers, String body, boolean canRetry) {
        HttpResponse<String> response = null;
        JsonObject payload = null;
        Exception error = null;

        try {
            var builder = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .timeout(Duration.ofSeconds(30));

            if (headers != null) {
                headers.forEach(builder::header);
            }
            if (body != null) {
                builder.POST(HttpRequest.BodyPublishers.ofString(body));
            }

            response = client.send(builder.build(), HttpResponse.BodyHandlers.ofString());
            payload = gson.fromJson(response.body(), JsonObject.class);
        } catch (Exception e) {
            error = e;
        }

        if (payload != null && payload.has("success") && payload.get("success").getAsBoolean()) {
            return payload.get("data");
        }

        int status = response != null ? response.statusCode() : 0;
        boolean isClientError = payload != null
            && payload.has("success") && !payload.get("success").getAsBoolean()
            && status >= 400 && status < 500 && status != 429;

        if (canRetry && !isClientError) {
            try {
                Thread.sleep(2000 + random.nextInt(3000));
            } catch (InterruptedException ignored) {}
            return fetchSgo(url, headers, body, false);
        }

        String errorMsg = payload != null && payload.has("error")
            ? payload.get("error").getAsString()
            : (error != null ? error.getMessage() : "Unknown");
        System.err.println("SGO Request Failed: " + status + " " + errorMsg);
        return null;
    }
}
ruby
require 'net/http'
require 'json'
require 'uri'

def fetch_sgo(url, options = {}, can_retry: true)
  response = nil
  payload = nil
  error = nil

  begin
    uri = URI(url)
    http = Net::HTTP.new(uri.host, uri.port)
    http.use_ssl = uri.scheme == 'https'

    request = Net::HTTP::Get.new(uri)
    options[:headers]&.each { |k, v| request[k] = v }

    response = http.request(request)
    payload = JSON.parse(response.body)
  rescue => e
    error = e
  end

  return payload['data'] if payload&.dig('success') == true

  status = response&.code&.to_i
  is_client_error = payload&.dig('success') == false &&
                    status && status >= 400 && status < 500 && status != 429

  if can_retry && !is_client_error
    sleep(2 + rand * 3)
    return fetch_sgo(url, options, can_retry: false)
  end

  error_msg = payload&.dig('error') || error&.message || 'Unknown'
  warn "SGO Request Failed: #{status} #{error_msg}"
  nil
end
php
<?php
function fetchSgo(string $url, array $options = [], bool $canRetry = true): mixed {
    $response = null;
    $payload = null;
    $error = null;
    $httpCode = 0;

    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => $options['headers'] ?? [],
        CURLOPT_TIMEOUT => 30,
    ]);

    $body = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error = curl_error($ch);
    curl_close($ch);

    if ($body !== false) {
        $payload = json_decode($body, true);
        if (json_last_error() !== JSON_ERROR_NONE) {
            $payload = null;
        }
    }

    if (isset($payload['success']) && $payload['success'] === true) {
        return $payload['data'] ?? null;
    }

    $isClientError = isset($payload['success']) && $payload['success'] === false
        && $httpCode >= 400 && $httpCode < 500 && $httpCode !== 429;

    if ($canRetry && !$isClientError) {
        usleep((2 + lcg_value() * 3) * 1_000_000);
        return fetchSgo($url, $options, false);
    }

    $errorMsg = $payload['error'] ?? $error ?: 'Unknown';
    error_log("SGO Request Failed: {$httpCode} {$errorMsg}");
    return null;
}



Need Help?

FAQ · Email · Chat · Discord