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

# Pharen API Authentication: API Keys and Bearer Tokens

> Authenticate every Pharen API request with a Bearer token API key or the X-API-Key header, including curl, Python, and Node.js code examples.

Every request you make to the Pharen API must be authenticated. Send a scoped API key as a Bearer token in the `Authorization` header. Without a valid key, the API returns `401 Unauthorized` and does not process the request.

## Generate an API key

You manage your API keys from inside the Pharen Hub dashboard:

1. Sign in to [pharen.app](https://pharen.app).
2. Navigate to **Settings → API Keys** in the left sidebar.
3. Click **New API Key**.
4. Give your key a descriptive name (e.g., `ci-pipeline` or `data-export-script`).
5. Choose an access target and scopes.
6. Copy the key immediately — it is only shown once in full at creation time.

<Warning>
  Treat your API key like a password. Anyone who holds it can make API calls on behalf of your workspace. Do not commit keys to source control, log them, or expose them in client-side code. Use environment variables or a secrets manager instead.
</Warning>

For a full walkthrough of key scopes, team targets, rotation, and storage, see [API keys](/api-reference/api-keys).

## Use your API key

Pass your API key as a Bearer token in the `Authorization` header of every HTTP request:

```bash theme={null}
Authorization: Bearer YOUR_API_KEY
```

The examples below call the calendar events endpoint. You can also use the interactive playground on each endpoint page.

<CodeGroup>
  ```bash curl theme={null}
  curl https://pharen.app/api/calendar/events/ \
    --request GET \
    --header "Authorization: Bearer YOUR_API_KEY" \
    --header "Content-Type: application/json"
  ```

  ```javascript JavaScript (fetch) theme={null}
  const response = await fetch("https://pharen.app/api/calendar/events/", {
    method: "GET",
    headers: {
      "Authorization": `Bearer ${process.env.PHAREN_API_KEY}`,
      "Content-Type": "application/json",
    },
  });

  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.error.message);
  }

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

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

  headers = {
      "Authorization": f"Bearer {os.environ['PHAREN_API_KEY']}",
      "Content-Type": "application/json",
  }

  response = requests.get(
      "https://pharen.app/api/calendar/events/",
      headers=headers,
  )
  response.raise_for_status()

  data = response.json()
  print(data)
  ```
</CodeGroup>

If your HTTP client cannot set a Bearer token, send the same key through `X-API-Key`:

```bash theme={null}
X-API-Key: YOUR_API_KEY
```

<Info>
  In the examples above, the API key is read from an environment variable (`PHAREN_API_KEY`). This is the recommended approach — it keeps secrets out of your codebase and makes rotating keys straightforward.
</Info>

## Authentication Errors

If your request cannot be authenticated, the API responds with one of the following errors:

| Status             | Code                       | Cause                                                                                 |
| ------------------ | -------------------------- | ------------------------------------------------------------------------------------- |
| `401 Unauthorized` | `missing_token`            | No `Authorization` header was present in the request.                                 |
| `401 Unauthorized` | `invalid_token`            | The token provided is malformed, expired, or does not exist.                          |
| `403 Forbidden`    | `insufficient_permissions` | The key is valid but lacks permission to access this resource or perform this action. |

An error response looks like this:

```json theme={null}
{
  "error": {
    "code": "invalid_token",
    "message": "The API key provided is invalid or has been revoked."
  }
}
```

## Revoking a Key

If a key is compromised or no longer needed, revoke it immediately from **Settings → API Keys** in the dashboard. Revoked keys stop working instantly. You can generate a replacement key at any time without disrupting other keys.

<Note>
  Rotating keys periodically is a good security practice, even if you have no reason to suspect a compromise. Consider setting a reminder to rotate production keys every 90 days.
</Note>

## Key scopes and permissions

API keys combine explicit key scopes with the permissions of the workspace member who created them. If that member's role is changed or their account is deactivated, all keys they created reflect the updated permissions or stop working.

For production integrations, create keys under a dedicated service account with only the scopes your integration requires. See the [API keys scope reference](/api-reference/api-keys#scope-reference) for the full list.
