> ## Documentation Index
> Fetch the complete documentation index at: https://docs.probalytics.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Error Codes

> API error responses and handling

All API errors return a consistent JSON structure with an HTTP status code.

## Error Response Format

```json theme={null}
{
  "message": "Human-readable error description",
  "data": {
    "field": "additional context"
  }
}
```

| Field     | Type      | Description                         |
| --------- | --------- | ----------------------------------- |
| `message` | `string`  | Error description                   |
| `data`    | `object?` | Additional error details (optional) |

***

## HTTP Status Codes

### 400 Bad Request

Invalid request parameters or malformed request.

```json theme={null}
{
  "message": "Invalid parameter: start_time must be RFC3339 format",
  "data": {
    "parameter": "start_time",
    "received": "2024-01-01"
  }
}
```

**Common causes:**

* Invalid date format (use RFC3339: `2024-01-01T00:00:00Z`)
* Invalid enum value for `platform`, `status`, or `side`
* `limit` exceeds maximum (1000)
* Invalid UUID format for `market_id`

### 401 Unauthorized

Missing or invalid authentication.

```json theme={null}
{
  "message": "Invalid API credentials"
}
```

**Common causes:**

* Missing `Authorization` header
* Incorrect format (should be `Bearer API_KEY_ID:API_KEY_SECRET`)
* Invalid or revoked API key
* Expired credentials

**Fix:**

```bash theme={null}
# Correct format
curl -H "Authorization: Bearer api_xxx:sk_xxx" \
  https://api.probalytics.io/api/v1/markets
```

### 403 Forbidden

Valid credentials but insufficient permissions.

```json theme={null}
{
  "message": "Access denied: upgrade required for this resource"
}
```

**Common causes:**

* Accessing data outside your plan's date range (Starter: 30 days)
* Requesting more data than your tier allows

### 429 Too Many Requests

Rate limit exceeded.

```json theme={null}
{
  "message": "Rate limit exceeded",
  "data": {
    "limit": 100,
    "window": "1 hour",
    "retry_after": 1800
  }
}
```

**Rate limits by tier:**

| Tier    | Requests/Hour |
| ------- | ------------- |
| Starter | 100           |
| Pro     | 1,000         |
| Custom  | Unlimited     |

**Handling rate limits:**

```python theme={null}
import time

response = requests.get(url, headers=headers)

if response.status_code == 429:
    retry_after = response.json().get("data", {}).get("retry_after", 60)
    time.sleep(retry_after)
    response = requests.get(url, headers=headers)
```

### 500 Internal Server Error

Unexpected server error.

```json theme={null}
{
  "message": "Internal server error"
}
```

**What to do:**

* Retry with exponential backoff
* If persistent, contact support with request details

***

## Error Handling Examples

### Python

```python theme={null}
import requests

API_KEY = "api_xxx:sk_xxx"
headers = {"Authorization": f"Bearer {API_KEY}"}

response = requests.get(
    "https://api.probalytics.io/api/v1/markets",
    headers=headers
)

if response.status_code == 200:
    markets = response.json()
elif response.status_code == 400:
    error = response.json()
    print(f"Bad request: {error['message']}")
elif response.status_code == 401:
    print("Check your API credentials")
elif response.status_code == 429:
    retry_after = response.json().get("data", {}).get("retry_after", 60)
    print(f"Rate limited. Retry in {retry_after} seconds")
else:
    print(f"Error {response.status_code}: {response.text}")
```

### JavaScript

```javascript theme={null}
const API_KEY = "api_xxx:sk_xxx";

const response = await fetch("https://api.probalytics.io/api/v1/markets", {
  headers: { "Authorization": `Bearer ${API_KEY}` }
});

if (response.ok) {
  const markets = await response.json();
} else {
  const error = await response.json();

  switch (response.status) {
    case 400:
      console.error("Bad request:", error.message);
      break;
    case 401:
      console.error("Check your API credentials");
      break;
    case 429:
      const retryAfter = error.data?.retry_after || 60;
      console.error(`Rate limited. Retry in ${retryAfter}s`);
      break;
    default:
      console.error(`Error ${response.status}:`, error.message);
  }
}
```

### Go

```go theme={null}
resp, err := http.Get(url)
if err != nil {
    log.Fatal(err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
    var apiError struct {
        Message string                 `json:"message"`
        Data    map[string]interface{} `json:"data"`
    }
    json.NewDecoder(resp.Body).Decode(&apiError)

    switch resp.StatusCode {
    case 400:
        log.Printf("Bad request: %s", apiError.Message)
    case 401:
        log.Println("Check your API credentials")
    case 429:
        log.Println("Rate limited")
    default:
        log.Printf("Error %d: %s", resp.StatusCode, apiError.Message)
    }
    return
}
```

***

## Retry Strategy

For transient errors (429, 500, 503), implement exponential backoff:

```python theme={null}
import time
import random

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

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

        if response.status_code in [429, 500, 503]:
            # Exponential backoff with jitter
            wait = (2 ** attempt) + random.uniform(0, 1)

            # Use server's retry-after if provided
            if response.status_code == 429:
                wait = response.json().get("data", {}).get("retry_after", wait)

            time.sleep(wait)
            continue

        # Non-retryable error
        response.raise_for_status()

    raise Exception("Max retries exceeded")
```

***

## Common Mistakes

### Wrong Authorization Format

```bash theme={null}
# Wrong: Missing Bearer
curl -H "Authorization: api_xxx:sk_xxx" ...

# Wrong: Only API Key ID
curl -H "Authorization: Bearer api_xxx" ...

# Correct
curl -H "Authorization: Bearer api_xxx:sk_xxx" ...
```

### Invalid Date Format

```bash theme={null}
# Wrong: Not RFC3339
?start_time=2024-01-01
?start_time=01/01/2024

# Correct: RFC3339 with timezone
?start_time=2024-01-01T00:00:00Z
```

### Exceeding Limits

```bash theme={null}
# Wrong: limit too high
?limit=5000

# Correct: max 1000, paginate for more
?limit=1000&offset=0
?limit=1000&offset=1000
```
