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

# Authentication

> One API key for everything in Chronicle. Twins have their own tokens.

## Your API key

Create a key in **Settings → API keys**. Give it a name, choose its scopes, and
copy the value; it's shown once. Keys start with `chr_`.

Pass it when you create the client, or set `CHRONICLE_API_KEY` and
`CHRONICLE_API_URL` in the environment and the client picks them up:

<CodeGroup dropdown>
  ```python Python theme={null}
  from chronicle import Chronicle

  client = Chronicle(api_key="chr_...", base_url="https://api.your-chronicle-deployment.com")
  # Or use: client = Chronicle() when the environment variables are set.
  ```

  ```typescript TypeScript theme={null}
  import { Chronicle } from "@chroniclelabs/sdk";

  const client = new Chronicle({ apiKey: "chr_...", baseURL: "https://api.your-chronicle-deployment.com" });
  // Or use: const client = new Chronicle(); when the environment variables are set.
  ```

  ```javascript JavaScript theme={null}
  import { Chronicle } from "@chroniclelabs/sdk";

  const client = new Chronicle({ apiKey: "chr_...", baseURL: "https://api.your-chronicle-deployment.com" });
  // Or use: const client = new Chronicle(); when the environment variables are set.
  ```

  ```go Go theme={null}
  import chronicle "github.com/chronicle-labs/chronicle-go"

  client := chronicle.NewClient(
      chronicle.WithAPIKey("chr_..."),
      chronicle.WithBaseURL("https://api.your-chronicle-deployment.com"),
  )
  // Or use: client := chronicle.NewClient() with environment variables set.
  ```

  ```rust Rust theme={null}
  use chronicle_sdk::{Chronicle, types::*};

  let client = Chronicle::builder()
      .api_key("chr_...")
      .base_url("https://api.your-chronicle-deployment.com")
      .build()?;
  // Or use: let client = Chronicle::from_env()?; with environment variables set.
  ```
</CodeGroup>

For Go and Rust, use the function context and imports in
[SDK setup](/api-reference/languages/overview#use-the-guide-examples) when
continuing to the key-creation example below.

A key belongs to one organization, and everything you create or read is scoped
to it. You never pass an organization ID.

## Scopes

Pick the scopes a key needs when you create it:

| Scope                         | Allows                                                                                                                             |
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `platform`                    | Worlds, twins, tasks, scorers, environments, evaluations, and reading agents. The default for a key you use from your own scripts. |
| `agents:write`                | Registering agent versions and recording runs. For the key your agent process holds.                                               |
| `events:write`, `events:read` | Sending and querying events.                                                                                                       |
| `traces:write`                | Sending spans, including OpenTelemetry.                                                                                            |
| `signals:write`               | Attaching feedback to events.                                                                                                      |

A CI key typically has `platform`. A key supplied to your agent process typically has
`agents:write` and `traces:write`. You can also create keys from code:

<CodeGroup dropdown>
  ```python Python theme={null}
  key = client.api_keys.create(name="billing-agent", scopes=["agents:write", "traces:write"])
  print(key.secret)  # shown once
  ```

  ```typescript TypeScript theme={null}
  const key = await client.apiKeys.create({ name: "billing-agent", scopes: ["agents:write", "traces:write"] });
  console.log(key.secret); // shown once
  ```

  ```javascript JavaScript theme={null}
  const key = await client.apiKeys.create({ name: "billing-agent", scopes: ["agents:write", "traces:write"] });
  console.log(key.secret); // shown once
  ```

  ```go Go theme={null}
  key, err := client.APIKeys.Create(ctx, chronicle.APIKeyCreateParams{
      Name:   "billing-agent",
      Scopes: []string{"agents:write", "traces:write"},
  })
  if err != nil {
      return err
  }
  fmt.Println(key.Secret) // shown once
  ```

  ```rust Rust theme={null}
  let key = client.api_keys().create(APIKeyCreateParams {
      name: "billing-agent".into(),
      scopes: vec!["agents:write".into(), "traces:write".into()],
  }).await?;
  println!("{}", key.secret); // shown once
  ```
</CodeGroup>

## Twin tokens

A running twin (a fake Slack, Linear, and so on) has its own `base_url` and
`token`. Use that token, not your Chronicle key, when your agent calls the
twin's vendor API. Read them from the world's `twins` list or
`client.twins.retrieve(twin_id)`. See [Twins](/api-reference/twins).

## Errors

| Status | Meaning                                                                              |
| ------ | ------------------------------------------------------------------------------------ |
| `401`  | Missing, invalid, or revoked key.                                                    |
| `403`  | The key lacks a scope, or your organization is out of capacity (for example, twins). |
| `404`  | Not found in your organization.                                                      |

The SDK raises `APIError` with the status and message. See
[Errors and retries](/api-reference/reliability).
