<!-- source: https://docs.redpine.ai/docs/authentication -->
# Authentication

> API keys, scoping, and the Bearer token header.

This page covers the REST API. Connecting an agent over MCP instead? Most MCP clients skip keys entirely and use a browser login. See [MCP](/docs/mcp).

## API keys

Create and manage API keys from your [API Keys](https://app.redpine.ai/api-keys?utm_source=docs\&utm_medium=referral) page in the dashboard. Keys are tied to your organization.

There are two kinds:

| Prefix     | Kind    | Behaviour                                                         |
| ---------- | ------- | ----------------------------------------------------------------- |
| `sk_live_` | Live    | Searches real content and spends credits                          |
| `sk_test_` | Sandbox | Returns canned results at no cost, never reaches licensed content |

Build against a sandbox key, then swap it for a live one. Nothing else about the request changes. See [Sandbox](/docs/sandbox) for what it covers.

## Header format

Include your API key in every request using the `Authorization` header:

```bash
Authorization: Bearer sk_live_YOUR_API_KEY
```

An `X-API-Key` header is also accepted, if that fits your HTTP client better:

```bash
X-API-Key: sk_live_YOUR_API_KEY
```

## Example request

The SDKs read `REDPINE_API_KEY` from the environment (falling back to `CONNECT_API_KEY`) and send the Bearer header for you. Pass the key explicitly only when the environment is not the right place for it, such as a request-scoped key in a multi-tenant service.

<CodeBlockTabs defaultValue="cURL" groupId="lang">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="cURL">
      cURL
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="Python">
      Python
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="TypeScript">
      TypeScript
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="Go">
      Go
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="cURL">
    ```bash  
    curl -X POST "https://api.redpine.ai/api/v1/search/query" \
      -H "Authorization: Bearer sk_live_abc123def456" \
      -H "Content-Type: application/json" \
      -d '{"collection": "my-collection", "query": "search text"}'
    ```
  </CodeBlockTab>

  <CodeBlockTab value="Python">
    ```python  
    from redpine import Redpine

    client = Redpine()                                # REDPINE_API_KEY
    client = Redpine(api_key="sk_live_abc123def456")  # explicit

    r = client.search("search text", collection="my-collection")
    ```
  </CodeBlockTab>

  <CodeBlockTab value="TypeScript">
    ```typescript  
    import { Redpine } from "@redpine-ai/sdk";

    const client = new Redpine();                                  // REDPINE_API_KEY
    const explicit = new Redpine({ apiKey: "sk_live_abc123def456" });

    const r = await client.search("search text", { collection: "my-collection" });
    ```
  </CodeBlockTab>

  <CodeBlockTab value="Go">
    ```go  
    client, err := redpine.New()                                     // REDPINE_API_KEY
    client, err = redpine.New(redpine.WithAPIKey("sk_live_abc123def456"))

    r, err := client.Search(ctx, "search text", redpine.SearchOptions{Collection: "my-collection"})
    ```
  </CodeBlockTab>
</CodeBlockTabs>

Constructing a client with no key available fails immediately with `AuthError` (Go: an error from `New`) rather than on the first request.

## Key scoping

API keys can be scoped to control access:

* **Organization-wide**: access all collections in your organization.
* **Collection-specific**: restrict access to one or more named collections. Requests to other collections return `403`.

## Authentication errors

If the API key is missing, the API returns `401 Unauthorized` with code `UNAUTHORIZED`. If it's present but doesn't match a live key, the code is `INVALID_API_KEY`; if it's been revoked, `API_KEY_REVOKED`:

```json
{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Authentication required",
    "requestId": "req_a1b2c3d4"
  }
}
```

If the key is valid but lacks access to the requested collection, the API returns `403 Forbidden` with code `NO_COLLECTION_ACCESS`. See [Errors](/docs/errors) for the full list of codes.

If a sandbox key reaches an endpoint that has no sandbox behaviour, the API returns `403 SANDBOX_UNSUPPORTED_ENDPOINT` rather than serving real data.

## Security best practices

* Never expose API keys in client-side code or public repositories.
* Use collection-scoped keys when possible to limit blast radius.
* Rotate keys periodically and revoke unused keys.
* Store keys in environment variables or a secrets manager.