# Error Codes and Troubleshooting
URL: https://sockodds.com/docs/info/errors/

# Error Codes and Troubleshooting [#error-codes-and-troubleshooting]

All API errors return an applicable HTTP status code along with this JSON body:

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

## TLDR [#tldr]

| Code | Meaning | Your action |
| --- | --- | --- |
| 200 | Success | Use the data |
| 400 | Bad Request | Fix parameters — check the error text |
| 401 | Unauthorized | Check API key header/parameter |
| 403 | Forbidden | The key is deactivated — contact support |
| 404 | Not Found | Verify the endpoint path |
| 429 | Rate Limited | Wait for `Retry-After`, then retry; upgrade if persistent |
| 500 | Server Error | Retry once after a delay |
| 501 | Not Implemented | `/stream/events` — poll instead |
| 503 | Service Unavailable | Wait and retry once |

## Types of errors [#types-of-errors]

### Non-standard response format [#non-standard-response-format]

An empty or non-JSON body means a transient network or server issue. Treat it as a 500: retry once after a short delay; contact support if it repeats.

### 400 Bad Request [#400-bad-request]

**Meaning:** invalid or missing parameters. Check the [reference](https://sockodds.com/docs/reference/); booleans must be `true`/`false`; dates ISO-8601; don't repeat a parameter; some combinations (`live=true` with `ended=true`) can't go together.

### 401 Unauthorized [#401-unauthorized]

**Meaning:** authentication failed or the key is missing. Send it as `x-api-key` (case-insensitive) or `apiKey`; check for whitespace; make sure you copied the key you were shown.

### 403 Forbidden [#403-forbidden]

**Meaning:** the key exists but is deactivated. Email support with the `keyID`.

### 404 Not Found [#404-not-found]

**Meaning:** the path doesn't exist. Make sure it starts with `/v2/`.

### 429 Too Many Requests [#429-too-many-requests]

**Meaning:** you exceeded your per-minute limit. Wait for `Retry-After` seconds; check `/account/usage`. A rejected call is counted for the minute but never billed.

### 500 Internal Server Error [#500-internal-server-error]

**Meaning:** something went wrong on our end. Retry once after a few seconds; if it persists contact support. Please don't retry in a tight loop.

### 501 Not Implemented [#501-not-implemented]

**Meaning:** you called `/v2/stream/events`. SockOdds does not stream; see the [polling guide](https://sockodds.com/docs/guides/realtime-streaming-api/).

### 503 Service Unavailable [#503-service-unavailable]

**Meaning:** temporarily unavailable. Wait and retry once.

## Error handling example [#error-handling-example]

**JavaScript** · **Python** · **Java** · **Ruby** · **PHP**

```javascript
async function fetchSockOdds(url, options = {}, canRetry = true) {
  let response, payload, error;
  try { response = await fetch(url, options); payload = await response.json(); } catch (e) { error = e; }
  if (payload?.success === true) return payload.data;
  const status = response?.status;
  if (status === 429 && canRetry) {
    await new Promise((r) => setTimeout(r, 1000 * Number(response.headers.get("retry-after") || 5)));
    return fetchSockOdds(url, options, false);
  }
  const isClientError = payload?.success === false && status >= 400 && status < 500;
  if (canRetry && !isClientError) {
    await new Promise((r) => setTimeout(r, 2000 + Math.random() * 3000));
    return fetchSockOdds(url, options, false);
  }
  console.error(`SockOdds request failed: ${status} ${payload?.error || error?.message}`);
  return null;
}
```

```python
import random, time, requests

def fetch_sirenodds(url, headers, can_retry=True):
    try:
        r = requests.get(url, headers=headers); payload = r.json()
    except Exception as e:
        r, payload = None, None
    if payload and payload.get("success") is True:
        return payload["data"]
    status = r.status_code if r is not None else None
    if status == 429 and can_retry:
        time.sleep(int(r.headers.get("Retry-After", "5"))); return fetch_sirenodds(url, headers, False)
    client_error = payload and payload.get("success") is False and status and 400 <= status < 500
    if can_retry and not client_error:
        time.sleep(2 + random.random() * 3); return fetch_sirenodds(url, headers, False)
    print("SockOdds request failed:", status, (payload or {}).get("error"))
    return None
```

```java
static JsonElement fetchSockOdds(String url, String key, boolean canRetry) throws Exception {
  var req = HttpRequest.newBuilder().uri(URI.create(url)).header("x-api-key", key).GET().build();
  var res = HttpClient.newHttpClient().send(req, HttpResponse.BodyHandlers.ofString());
  var payload = JsonParser.parseString(res.body()).getAsJsonObject();
  if (payload.has("success") && payload.get("success").getAsBoolean()) return payload.get("data");
  int status = res.statusCode();
  if (status == 429 && canRetry) { Thread.sleep(1000L * Long.parseLong(res.headers().firstValue("retry-after").orElse("5"))); return fetchSockOdds(url, key, false); }
  boolean clientError = status >= 400 && status < 500;
  if (canRetry && !clientError) { Thread.sleep(2000 + new Random().nextInt(3000)); return fetchSockOdds(url, key, false); }
  System.err.println("SockOdds request failed: " + status + " " + payload.get("error"));
  return null;
}
```

```ruby
def fetch_sirenodds(url, key, can_retry: true)
  uri = URI(url); req = Net::HTTP::Get.new(uri); req["x-api-key"] = key
  res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |h| h.request(req) }
  payload = JSON.parse(res.body) rescue nil
  return payload["data"] if payload&.dig("success") == true
  status = res.code.to_i
  if status == 429 && can_retry
    sleep(res["retry-after"].to_i.nonzero? || 5); return fetch_sirenodds(url, key, can_retry: false)
  end
  client_error = payload&.dig("success") == false && status.between?(400, 499)
  if can_retry && !client_error
    sleep(2 + rand * 3); return fetch_sirenodds(url, key, can_retry: false)
  end
  warn "SockOdds request failed: #{status} #{payload&.dig('error')}"; nil
end
```

```php
function fetchSockOdds(string $url, string $key, bool $canRetry = true) {
  $ch = curl_init($url); curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => ["x-api-key: $key"], CURLOPT_TIMEOUT => 30]);
  $body = curl_exec($ch); $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch);
  $payload = $body !== false ? json_decode($body, true) : null;
  if (($payload['success'] ?? false) === true) return $payload['data'];
  if ($status === 429 && $canRetry) { sleep(5); return fetchSockOdds($url, $key, false); }
  $clientError = ($payload['success'] ?? null) === false && $status >= 400 && $status < 500;
  if ($canRetry && !$clientError) { usleep((2 + lcg_value() * 3) * 1000000); return fetchSockOdds($url, $key, false); }
  error_log("SockOdds request failed: $status " . ($payload['error'] ?? 'Unknown'));
  return null;
}
```

> Need help?[FAQ](https://sockodds.com/docs/faq/) · [Email](mailto:api@sockodds.com) · [Contact](https://sockodds.com/contact-us/)
