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

# Introduction

> The TruLayer HTTP API — base URL, authentication, errors, versioning.

All TruLayer endpoints live under a single base URL and share one authentication scheme. The full endpoint list is auto-generated from our OpenAPI spec — use the sidebar to browse every route with request/response shapes and a live playground.

## Base URL

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

All endpoints below this base use the `/v1/` path prefix (e.g. `/v1/ingest`, `/v1/traces`).

## Authentication

Every request requires a bearer token in the `Authorization` header.

```http theme={null}
Authorization: Bearer <token>
```

Two token types are accepted:

| Client                  | Token              | How to get it                                                              |
| ----------------------- | ------------------ | -------------------------------------------------------------------------- |
| **SDKs / server code**  | API key (`tl_...`) | Dashboard → Settings → API keys                                            |
| **Dashboard / browser** | Clerk session JWT  | Managed automatically by the frontend — you do not construct these by hand |

API keys are tenant-scoped. They have access to every project in your organisation and are long-lived until revoked. **Never embed them in client-side code** — always call the TruLayer API from your server, or use a short-lived Clerk session token from an authenticated browser.

## Content type

All request and response bodies are JSON unless otherwise noted:

```http theme={null}
Content-Type: application/json
```

## Rate limits

Rate limits are per tenant, enforced via a fixed window (1-minute buckets):

| Endpoint family                            | Limit (Starter)       | Limit (Pro)       |
| ------------------------------------------ | --------------------- | ----------------- |
| `POST /v1/ingest`, `POST /v1/ingest/batch` | 50,000 traces / month | 1,000,000 / month |
| `POST /v1/feedback`, `POST /v1/eval`       | Scales with plan      | Scales with plan  |
| `GET /v1/traces`, `GET /v1/metrics`        | 60 rps                | 600 rps           |

When a limit is exceeded you get HTTP **429**. Check the `X-RateLimit-*` headers on every response for the current window state. Enterprise plans have no hard limits.

## Error format

Errors always return a JSON body of this shape:

```json theme={null}
{
  "error": "Trace not found."
}
```

The `error` field is a human-readable string. Machine-parseable error codes (where applicable) are returned in dedicated fields specific to each endpoint — for example, `POST /v1/eval` returns `{"code": "eval_quota_exceeded", "error": "..."}` when the monthly eval quota is exceeded.

| Status | Meaning                                                                                                                                                                                      |
| ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | Malformed request — body doesn't match schema                                                                                                                                                |
| `401`  | Missing or invalid token                                                                                                                                                                     |
| `402`  | Plan upgrade required — feature is not available on the tenant's current plan. Body includes `code: "plan_upgrade_required"` and `required_plan` (the lowest plan that unlocks the feature). |
| `403`  | Token valid but not authorised for this resource (e.g. wrong tenant, or archived project — see below)                                                                                        |
| `404`  | Resource not found                                                                                                                                                                           |
| `409`  | Conflict — e.g. submitting a trace with an ID that already exists, or a constraint violation                                                                                                 |
| `422`  | Validation error on a required field                                                                                                                                                         |
| `429`  | Rate-limited                                                                                                                                                                                 |
| `5xx`  | Server-side issue — safe to retry with exponential backoff                                                                                                                                   |

### Machine-readable error codes

Some errors include a `code` field alongside the human-readable `error` string. Use the `code` value for programmatic handling — the `error` string is subject to change without notice.

| Code                                | Status | Endpoints                                                          | Description                                                                                                                                                  |
| ----------------------------------- | ------ | ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `error.project.archived`            | `403`  | `POST /v1/ingest`, `POST /v1/ingest/batch`, `POST /v1/otlp/traces` | The project associated with the API key has been archived. Ingest is suspended for the duration. Unarchive the project from **Projects settings** to resume. |
| `error.project.cannot_archive_last` | `409`  | `POST /v1/projects/{id}/archive`                                   | Returned when attempting to archive the tenant's last active project. At least one active project must exist at all times.                                   |
| `plan_upgrade_required`             | `402`  | Various                                                            | Feature not available on the current plan. Response also includes `required_plan`.                                                                           |
| `eval_quota_exceeded`               | `402`  | `POST /v1/eval`                                                    | Monthly eval quota exhausted.                                                                                                                                |
| `eval_rules_quota_exceeded`         | `402`  | `POST /v1/eval-rules`                                              | Starter tenant already has 3 eval rules, which is the plan cap. Delete an existing rule or upgrade to Pro to create more.                                    |

Always log the `request_id` — it's the fastest way for support to look up a failed request.

## Versioning

The current API version is **v1**. Backwards-incompatible changes are shipped as a new version path (`/v2/...`); v1 is supported for at least 12 months after v2 release.

Additive changes (new fields, new optional parameters) may land on v1 without a version bump — client code should ignore unknown response fields.

## SDKs

For most apps, you should not hit these endpoints directly — the SDKs handle batching, retries, and serialisation for you.

<CardGroup cols={2}>
  <Card title="Python SDK" icon="python" href="/sdks/python/overview">
    `pip install trulayer`
  </Card>

  <Card title="TypeScript SDK" icon="js" href="/sdks/typescript/overview">
    `npm install @trulayer/sdk`
  </Card>
</CardGroup>

## Making a raw request

If you need to call the API from a language without an SDK, or for debugging:

<CodeGroup>
  ```bash curl theme={null}
  curl https://api.trulayer.ai/v1/traces \
    -H "Authorization: Bearer $TRULAYER_API_KEY"
  ```

  ```python Python (httpx) theme={null}
  import os, httpx

  response = httpx.get(
      "https://api.trulayer.ai/v1/traces",
      headers={"Authorization": f"Bearer {os.environ['TRULAYER_API_KEY']}"},
  )
  response.raise_for_status()
  print(response.json())
  ```

  ```typescript TypeScript (fetch) theme={null}
  const response = await fetch("https://api.trulayer.ai/v1/traces", {
    headers: { Authorization: `Bearer ${process.env.TRULAYER_API_KEY}` },
  });
  if (!response.ok) throw new Error(`${response.status}`);
  console.log(await response.json());
  ```
</CodeGroup>

Ready to explore? Pick an endpoint in the sidebar.
