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

# Authentication

> How to authenticate your requests to the Nuvia API with an API key

Every request to the Nuvia API is authenticated with a **Bearer token** sent in the
`Authorization` header. This page explains how to authenticate calls with an API key you **already
have**. To generate, list, and revoke keys, see the [API key guide](/en/guia-api-key).

## Base URL

```
https://api.nuvia.ai
```

All REST API routes use the version prefix `/v1`. For example, listing agents is
`GET https://api.nuvia.ai/v1/agents`.

<Warning>
  The Nuvia API key **doesn't** use an `X-API-Key` header or a token in the `sk_...` format. The
  key is sent as a **Bearer token** in the `Authorization` header:

  ```
  Authorization: Bearer <your-api-key>
  ```

  Sending the key in `X-API-Key` results in `401`, because the server doesn't read that header.
</Warning>

## Two ways to authenticate

The API accepts two types of identity **in the same** `Authorization: Bearer` header:

* **Company API key**: this is what you use for **programmatic integration**. The key is linked
  to your company and to the scopes defined at creation; it can have an optional expiration
  (`expiresAt`). It's the recommended method for servers, scripts, and integrations.
* **Human JWT**: the session token issued by the application's login flow
  (`POST /v1/auth/login`). It represents a human user, not an integration. You don't need it to
  consume the API via API key. The login endpoints belong to the platform and **don't appear in
  the [API reference](/en/api-reference)**, which covers the surface consumable by API key.

The server automatically identifies which of the two was sent from the token's content itself.
You don't flag the type anywhere. For the rest of this documentation, we assume the use of a
**company API key**.

## Authenticating a request

Include the `Authorization` header in every call. The example below lists your company's agents
(requires the `agents:read` scope):

<CodeGroup>
  ```bash cURL theme={null}
  curl https://api.nuvia.ai/v1/agents \
    -H "Authorization: Bearer $NUVIA_API_KEY"
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch("https://api.nuvia.ai/v1/agents", {
    headers: {
      Authorization: `Bearer ${process.env.NUVIA_API_KEY}`,
    },
  });

  const data = await res.json();
  ```

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

  res = requests.get(
      "https://api.nuvia.ai/v1/agents",
      headers={"Authorization": f"Bearer {os.environ['NUVIA_API_KEY']}"},
  )

  data = res.json()
  ```
</CodeGroup>

<Note>
  The API key is a **full access token** to the granted scope. Treat it as a secret: store it in
  an environment variable or secrets vault, never in source code or version control.
</Note>

## Multi-tenant and the `X-Company-Id` header

The tenant (company) of a company API key is resolved **by the token itself**. You don't need to
provide it. The `X-Company-Id` header is only required for internal-use global keys and is
**ignored** for company API keys and for human JWTs. In short: **when integrating with a company
API key, you don't send `X-Company-Id`.**

## Authentication errors

Authentication error responses follow the `{ statusCode, message, error }` format.

### 401: not authenticated

Returned when the token is missing, invalid, expired, or revoked.

```json theme={null}
{
  "statusCode": 401,
  "message": "Invalid authentication",
  "error": "Unauthorized"
}
```

The `message` field details the cause when possible, for example `"Invalid API key"`,
`"Expired API key"`, `"Revoked API key"`, or `"API key not found"`.

### 403: no permission

Returned when the token is valid, but the API key **doesn't have the scope** required for the
action, or the endpoint isn't available for API keys.

```json theme={null}
{
  "statusCode": 403,
  "message": "API key doesn't have the scope required for this action",
  "error": "Forbidden"
}
```

If you get `403` on a call that should work, check whether the key was created with the scope
required by the endpoint. Scopes are defined when the key is created. See the
[API key guide](/en/guia-api-key).

## Next steps

<CardGroup cols={2}>
  <Card title="API key guide" icon="key" href="/en/guia-api-key">
    How to generate, list, and revoke keys, and which scopes exist.
  </Card>

  <Card title="Quickstart" icon="rocket" href="/en/quickstart">
    Make your first API call in a few minutes.
  </Card>
</CardGroup>
