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

# Introduction

> Learn how to authenticate, handle errors, and understand rate limits for the Bodyguard Analyze API.

The Bodyguard Analyze API classifies **text**, **images**, and **usernames** for harmful or undesirable content. All requests are made over HTTPS to:

```text theme={null}
https://api.bodyguard.ai
```

`api.bodyguard.ai` is a global endpoint that should be used by default. `api.bodyguard.ai` is located in the Bruxelles (Belgium) area.

### Regional endpoints

For lower latency, you can send requests directly to a specific region:

| Region  | Location               | Base URL                       |
| ------- | ---------------------- | ------------------------------ |
| US East | Northern Virginia, USA | `https://api.us1.bodyguard.ai` |
| US West | California, USA        | `https://api.us2.bodyguard.ai` |

<Note>
  Regional endpoints expose the same API as the global endpoint — only the base URL changes. Your API key works across all regions.
</Note>

## Quickstart

The following example analyzes a text message. Replace `<your-api-key>` and `<your-channel-id>` with values provided by Bodyguard.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.bodyguard.ai/analyze/v1/text \
    -H "Authorization: ApiKey <your-api-key>" \
    -H "Content-Type: application/json" \
    -d '{
      "channelId": "<your-channel-id>",
      "text": "Einstein is an asshole",
      "publishedAt": "2026-04-23T10:30:00.000Z"
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("https://api.bodyguard.ai/analyze/v1/text", {
    method: "POST",
    headers: {
      Authorization: "ApiKey <your-api-key>",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      channelId: "<your-channel-id>",
      text: "Einstein is an asshole",
      publishedAt: "2026-04-23T10:30:00.000Z",
    }),
  });

  const result = await response.json();
  console.log(result);
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api.bodyguard.ai/analyze/v1/text",
      headers={
          "Authorization": "ApiKey <your-api-key>",
          "Content-Type": "application/json",
      },
      json={
          "channelId": "<your-channel-id>",
          "text": "Einstein is an asshole",
          "publishedAt": "2026-04-23T10:30:00.000Z",
      },
  )

  print(response.json())
  ```

  ```go Go theme={null}
  package main

  import (
  	"bytes"
  	"encoding/json"
  	"fmt"
  	"io"
  	"net/http"
  )

  func main() {
  	body, _ := json.Marshal(map[string]string{
  		"channelId":   "<your-channel-id>",
  		"text":        "Einstein is an asshole",
  		"publishedAt": "2026-04-23T10:30:00.000Z",
  	})

  	req, _ := http.NewRequest("POST", "https://api.bodyguard.ai/analyze/v1/text", bytes.NewReader(body))
  	req.Header.Set("Authorization", "ApiKey <your-api-key>")
  	req.Header.Set("Content-Type", "application/json")

  	resp, err := http.DefaultClient.Do(req)
  	if err != nil {
  		panic(err)
  	}
  	defer resp.Body.Close()

  	out, _ := io.ReadAll(resp.Body)
  	fmt.Println(string(out))
  }
  ```
</CodeGroup>

To interpret the response, see the [text classifications taxonomy](/en/documentation/taxonomy/text-classifications).

## Authentication

All requests must include an `Authorization` header using the `ApiKey` scheme. The scheme name is case-sensitive — `ApiKey` must be written exactly as shown.

### Required request headers

| Header          | Value                   |
| --------------- | ----------------------- |
| `Authorization` | `ApiKey <your-api-key>` |
| `Content-Type`  | `application/json`      |

Your API key is provided by Bodyguard. Keep it secret and never expose it in client-side code.

### Authentication errors

All authentication failures return a `401 Unauthorized` response with the `AUTHENTICATION_ERROR` code and one of the following reasons:

| Condition                   | `reason`                      |
| --------------------------- | ----------------------------- |
| Invalid or unrecognised key | `REASON_INVALID_CREDENTIALS`  |
| Key has expired             | `REASON_EXPIRED_CREDENTIALS`  |
| Key has been disabled       | `REASON_DISABLED_CREDENTIALS` |

The reason is returned inside the error envelope's `details.authenticationError.reason` field. See [Errors](#errors) for the full response format and a worked example.

## Versioning

Endpoints live under a versioned path — for example, `/analyze/v1/text`. The `/v1/` endpoints are stable and Bodyguard commits to their API stability. Any breaking change will be introduced under a new version path (for example `/v2/`), allowing you to migrate on your own schedule.

## Rate limits

Rate limits are enforced **per organisation**. Each endpoint has its own independent quota. Quotas are customer-specific and negotiated as part of your contract.

When your organisation exceeds a quota, the API returns `429 Too Many Requests` with the `QUOTA_ERROR` code. The response envelope's `details.quotaError.violations` array identifies which specific quota was exceeded.

```json theme={null}
{
  "error": {
    "code": "QUOTA_ERROR",
    "details": {
      "quotaError": {
        "violations": [
          {
            "quotaName": "analyze.message.requests_per_second",
            "quotaValue": 10
          }
        ]
      }
    }
  }
}
```

Need a quota adjustment? [Contact us](https://www.bodyguard.ai/contact-us).

## Errors

All errors follow a consistent JSON envelope:

```json theme={null}
{
  "error": {
    "code": "<error-code>",
    "details": { }
  }
}
```

The `details` object contains structured information specific to the error type and has exactly one field whose name matches the error code (e.g. `badRequestError` for `BAD_REQUEST_ERROR`). The `Content-Type` of error responses is always `application/json`.

### Error codes

| HTTP status               | `code`                      | `details` payload                                         | When it occurs                                                                                                        |
| ------------------------- | --------------------------- | --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| `400 Bad Request`         | `BAD_REQUEST_ERROR`         | `badRequestError.fieldViolations[]`                       | A required field is missing or a field value is invalid. The `fieldViolations` array identifies each offending field. |
| `401 Unauthorized`        | `AUTHENTICATION_ERROR`      | `authenticationError.reason`                              | The API key is missing, invalid, expired, or disabled.                                                                |
| `403 Forbidden`           | `PERMISSION_DENIED_ERROR`   | `permissionDeniedError.permission`, `.resourceIdentifier` | The API key does not have permission to perform the requested action on the resource.                                 |
| `404 Not Found`           | `NOT_FOUND_ERROR`           | `notFoundError.resourceIdentifier`                        | The requested resource does not exist.                                                                                |
| `409 Conflict`            | `CONFLICT_ERROR`            | `conflictError.reason`                                    | The request conflicts with the current state of a resource.                                                           |
| `412 Precondition Failed` | `PRECONDITION_FAILED_ERROR` | `preconditionFailedError.reason`                          | A precondition required for the request was not met.                                                                  |
| `429 Too Many Requests`   | `QUOTA_ERROR`               | `quotaError.violations[]`                                 | Your organisation has exceeded its rate limit. See [Rate limits](#rate-limits).                                       |
| `503 Service Unavailable` | `TRANSIENT_ERROR`           | `transientError.reason`                                   | A transient server-side issue prevented the request from being processed. Safe to retry with backoff.                 |

### Example: bad request

```json theme={null}
{
  "error": {
    "code": "BAD_REQUEST_ERROR",
    "details": {
      "badRequestError": {
        "fieldViolations": [
          {
            "field": "text",
            "message": "field is required"
          }
        ]
      }
    }
  }
}
```

### Example: authentication failure

```json theme={null}
{
  "error": {
    "code": "AUTHENTICATION_ERROR",
    "details": {
      "authenticationError": {
        "reason": "REASON_INVALID_CREDENTIALS"
      }
    }
  }
}
```

### Example: transient failure

```json theme={null}
{
  "error": {
    "code": "TRANSIENT_ERROR",
    "details": {
      "transientError": {
        "reason": "upstream service temporarily unavailable"
      }
    }
  }
}
```

Retry `TRANSIENT_ERROR` responses with exponential backoff. All other error codes should not be retried without addressing the underlying cause.

## Next steps

<Card title="Key concepts" icon="book-open" href="/en/api-reference/concepts">
  Learn the core building blocks of the Bodyguard API: organizations, sources, channels, references, and publication dates.
</Card>
