Documentation
Platform API Overview

Error Handling

Interpret ALT Sports Data API error responses and build resilient clients.

Error Handling

Color-coded HTTP status codes at a glance
Decision tree diagram for handling API errors: success, client errors, rate limits, and server errors.

The ALT Sports Data API uses standard HTTP status codes and returns structured error bodies so you can diagnose problems programmatically, not just by reading messages.

HTTP status codes

CodeStatusWhen you will see it
200OKRequest succeeded
201CreatedResource created successfully
400Bad RequestA query parameter or request body is invalid
401UnauthorizedAPI key is missing or malformed
403ForbiddenAPI key is valid but lacks permission for this resource
404Not FoundThe requested resource does not exist
429Too Many RequestsYou have exceeded your rate limit -- see Rate Limits
500Internal Server ErrorSomething went wrong on our side
503Service UnavailableTemporary disruption; safe to retry after a short delay

Error response format

Every error response follows the same structure:

{
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable explanation of what went wrong",
    "details": {
      "field": "Additional context, if available"
    }
  }
}

The code field is a stable machine-readable identifier. The message field is meant for logs and developer debugging -- do not display it to end users.

Common errors and how to fix them

INVALID_API_KEY (401)

{
  "error": {
    "code": "INVALID_API_KEY",
    "message": "The provided API key is invalid or has been revoked"
  }
}

Fix: Verify that your key is correct and has not been rotated. Check that the header name is Authorization: Bearer <key> or X-API-Key: <key>.

VALIDATION_ERROR (400)

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid request parameters",
    "details": {
      "limit": "Must be between 1 and 100",
      "offset": "Must be a non-negative integer"
    }
  }
}

Fix: Check the details object -- it tells you exactly which parameter failed and why. Correct the value and retry.

RESOURCE_NOT_FOUND (404)

{
  "error": {
    "code": "RESOURCE_NOT_FOUND",
    "message": "Event with ID 'evt_abc123' not found"
  }
}

Fix: Confirm the resource ID is valid. IDs are case-sensitive. If you received the ID from a previous call, the resource may have been removed or the event may have concluded.

RATE_LIMIT_EXCEEDED (429)

{
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Rate limit exceeded. Please retry after 1678886400",
    "retry_after": 1678886400
  }
}

Fix: Wait until the retry_after timestamp, then retry. See Rate Limits for backoff strategies.

Building a resilient API client

The following example handles authentication errors, validation failures, rate limits, and transient server errors in one function.

import requests
import time

API_BASE = "https://api.altsportsdata.com/api/v1/public"

def asd_request(path, headers, params=None, max_retries=3):
    """Make a request to ALT Sports Data with automatic retry on transient errors."""
    url = f"{API_BASE}/{path}"

    for attempt in range(max_retries):
        response = requests.get(url, headers=headers, params=params)

        if response.status_code == 200:
            return response.json()

        error = response.json().get("error", {})
        code = error.get("code", "UNKNOWN")

        if response.status_code == 401:
            raise ValueError(f"Authentication failed: {error.get('message')}")

        if response.status_code == 400:
            raise ValueError(f"Validation error: {error.get('details', error.get('message'))}")

        if response.status_code == 404:
            return None  # Resource does not exist

        if response.status_code == 429:
            wait = max(int(error.get("retry_after", time.time() + 5)) - int(time.time()), 1)
            print(f"Rate limited. Retrying in {wait}s...")
            time.sleep(wait)
            continue

        if response.status_code >= 500:
            wait = 2 ** attempt
            print(f"Server error ({response.status_code}). Retrying in {wait}s...")
            time.sleep(wait)
            continue

        response.raise_for_status()

    raise Exception(f"Request failed after {max_retries} retries")
const API_BASE = "https://api.altsportsdata.com/api/v1/public";

async function asdRequest(path, headers, maxRetries = 3) {
  const url = `${API_BASE}/${path}`;

  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const response = await fetch(url, { headers });

    if (response.ok) {
      return await response.json();
    }

    const body = await response.json();
    const error = body.error || {};

    if (response.status === 401) {
      throw new Error(`Authentication failed: ${error.message}`);
    }

    if (response.status === 400) {
      throw new Error(`Validation error: ${JSON.stringify(error.details || error.message)}`);
    }

    if (response.status === 404) {
      return null; // Resource does not exist
    }

    if (response.status === 429) {
      const wait = Math.max((error.retry_after || Math.floor(Date.now() / 1000) + 5) - Math.floor(Date.now() / 1000), 1);
      console.log(`Rate limited. Retrying in ${wait}s...`);
      await new Promise((r) => setTimeout(r, wait * 1000));
      continue;
    }

    if (response.status >= 500) {
      const wait = 2 ** attempt;
      console.log(`Server error (${response.status}). Retrying in ${wait}s...`);
      await new Promise((r) => setTimeout(r, wait * 1000));
      continue;
    }

    throw new Error(`Unexpected error: ${response.status}`);
  }

  throw new Error(`Request failed after ${maxRetries} retries`);
}

Best practices

  1. Branch on status code first, then on error.code -- the status code tells you the category, the error code tells you the specific problem
  2. Retry only on transient errors -- 429, 500, and 503 are safe to retry; 400, 401, and 403 are not
  3. Log the full error body -- the message and details fields contain the information you need to debug
  4. Never surface raw error messages to end users -- parse the structured response and show a user-friendly message instead
  5. Set reasonable timeouts -- if the API does not respond within 10-15 seconds, treat it as a transient failure and retry

On this page