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

# FraudTrace AI API Error Codes and Troubleshooting Guide

> Understand every FraudTrace AI API error code, what triggers each one, how to resolve it, and when to retry or skip retrying failed requests.

When a request to the FraudTrace AI API cannot be completed successfully, the API returns an HTTP error status code alongside a JSON body that describes what went wrong. Understanding these codes and building appropriate error handling into your integration will make your application more resilient and easier to debug in production.

## Error Response Format

Every error response uses the same JSON structure regardless of the status code. The `error` field contains a machine-readable code you can use for programmatic handling, while `message` provides a human-readable explanation.

```json theme={null}
{
  "error": "unauthorized",
  "message": "API key is missing or invalid."
}
```

<Info>
  Always check the `error` field — not just the HTTP status code — when building error-handling logic. The `error` value is stable and versioned; the `message` text may change over time.
</Info>

## Error Code Reference

The table below covers every error code the API can return, what triggers it, and how to resolve it.

| HTTP Status | Error Code            | Description                                  | Resolution                                                                                   |
| ----------- | --------------------- | -------------------------------------------- | -------------------------------------------------------------------------------------------- |
| `400`       | `bad_request`         | Missing or invalid request parameters        | Check that all required query parameters and body fields are present and correctly formatted |
| `401`       | `unauthorized`        | API key is missing or invalid                | Verify your `Authorization: Bearer` token is correct and has not been rotated                |
| `404`       | `not_found`           | Endpoint or resource not found               | Check the URL path for typos; confirm the resource ID exists                                 |
| `422`       | `validation_error`    | Request body failed schema validation        | Review the `message` field for specifics and correct your request body                       |
| `429`       | `rate_limit_exceeded` | Too many requests sent in the current window | Implement exponential backoff and retry after the period indicated by `Retry-After`          |
| `500`       | `internal_error`      | Unexpected server-side error                 | Retry with backoff; contact support if the error persists                                    |
| `503`       | `service_unavailable` | Service is temporarily unavailable           | Retry with exponential backoff; check the FraudTrace status page                             |

## Common Error Examples

### 401 Unauthorized

Returned when the `Authorization` header is missing, malformed, or contains an invalid API key.

```json theme={null}
{
  "error": "unauthorized",
  "message": "API key is missing or invalid."
}
```

**Common causes:**

* The `Authorization` header is missing entirely.
* The token is prefixed incorrectly (e.g. `Token` or `Basic` instead of `Bearer`).
* The API key has been rotated or revoked in the dashboard.

***

### 400 Bad Request

Returned when a required parameter is absent or a parameter value is in the wrong format.

```json theme={null}
{
  "error": "bad_request",
  "message": "The 'upi' query parameter is required."
}
```

**Common causes:**

* The `upi` query parameter is missing from a `GET /v1/verify/upi` request.
* A UPI VPA is not in valid `handle@provider` format.
* A batch request body is missing the `vpas` array.

***

### 429 Rate Limit Exceeded

Returned when you send more requests than your plan's rate limit allows within a given window.

```json theme={null}
{
  "error": "rate_limit_exceeded",
  "message": "You have exceeded your request limit. Please retry after 14 seconds.",
  "retry_after": 14
}
```

The response also includes a `Retry-After` header (in seconds) that tells you exactly how long to wait before sending the next request. See [Rate Limits](/api-reference/rate-limits) for the full breakdown of headers and handling guidance.

<Warning>
  Do not immediately retry a `429` response. Hammering the API after a rate-limit error will not accelerate recovery and may extend your backoff window.
</Warning>

## Retry Strategy

Different error codes call for different retry behaviors. The wrong strategy — such as retrying a `400` — wastes quota and delays diagnosis.

### When to Retry

| Status Code | Retry? | Strategy                                     |
| ----------- | ------ | -------------------------------------------- |
| `400`       | ❌ No   | Fix the request before retrying              |
| `401`       | ❌ No   | Verify your API key                          |
| `404`       | ❌ No   | Fix the URL or resource ID                   |
| `422`       | ❌ No   | Fix the request body                         |
| `429`       | ✅ Yes  | Exponential backoff — read `Retry-After`     |
| `500`       | ✅ Yes  | Retry up to 3 times with backoff             |
| `503`       | ✅ Yes  | Retry up to 3 times with exponential backoff |

### Exponential Backoff Rules

* **429:** Start at **1 second**, double on each attempt, cap at **32 seconds**. Add random jitter (±0–500 ms) to prevent thundering-herd effects when multiple clients hit the limit simultaneously.
* **500 / 503:** Retry up to **3 times** using the same doubling pattern (1s → 2s → 4s).
* **4xx (except 429):** Do **not** retry. The request is semantically invalid — retrying will produce the same error.

### Python Retry Example

The example below shows two approaches: a simple manual loop and a cleaner implementation using the `tenacity` library.

<CodeGroup>
  ```python Manual Retry Loop theme={null}
  import time
  import requests

  def verify_upi(vpa: str, api_key: str, max_retries: int = 4) -> dict:
      base_delay = 1  # seconds
      max_delay = 32

      for attempt in range(max_retries):
          response = requests.get(
              "https://api.fraudtraceai.com/v1/verify/upi",
              params={"upi": vpa},
              headers={"Authorization": f"Bearer {api_key}"},
          )

          if response.status_code == 429:
              retry_after = int(response.headers.get("Retry-After", base_delay * (2 ** attempt)))
              wait = min(retry_after, max_delay)
              print(f"Rate limited. Retrying in {wait}s (attempt {attempt + 1}/{max_retries})")
              time.sleep(wait)
              continue

          if response.status_code in (500, 503):
              if attempt < max_retries - 1:
                  wait = min(base_delay * (2 ** attempt), max_delay)
                  print(f"Server error {response.status_code}. Retrying in {wait}s")
                  time.sleep(wait)
                  continue

          # For 4xx errors (except 429 already handled), raise immediately — do not retry
          response.raise_for_status()
          return response.json()

      raise Exception(f"Request failed after {max_retries} attempts")
  ```

  ```python Tenacity Library theme={null}
  import requests
  from tenacity import (
      retry,
      stop_after_attempt,
      wait_exponential,
      retry_if_exception,
      before_sleep_log,
  )
  import logging

  logger = logging.getLogger(__name__)

  def _is_retryable(exc: Exception) -> bool:
      if isinstance(exc, requests.HTTPError):
          return exc.response.status_code in (429, 500, 503)
      return False

  @retry(
      retry=retry_if_exception(_is_retryable),
      wait=wait_exponential(multiplier=1, min=1, max=32),
      stop=stop_after_attempt(4),
      before_sleep=before_sleep_log(logger, logging.WARNING),
  )
  def verify_upi(vpa: str, api_key: str) -> dict:
      response = requests.get(
          "https://api.fraudtraceai.com/v1/verify/upi",
          params={"upi": vpa},
          headers={"Authorization": f"Bearer {api_key}"},
      )
      response.raise_for_status()
      return response.json()
  ```
</CodeGroup>

<Tip>
  If you are processing large volumes of VPAs, use the batch endpoint (`POST /v1/verify/upi/batch`) to verify up to 100 VPAs in a single request. This reduces the total number of API calls and makes rate limit management much simpler.
</Tip>

## Getting Help

If you consistently receive `500` errors that do not resolve after retrying, or if you believe an error is caused by a platform issue rather than a request problem, contact the FraudTrace AI support team with the full response body and the timestamp of the failing request. Including the `X-Request-Id` response header (if present) will significantly speed up diagnosis.
