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

# Authentication

> Learn how to create, manage, and use API keys for authenticating with the nunu.ai API

All nunu.ai API requests require authentication using an API key. This page covers how to create, manage, and use API keys.

## Creating API Keys

<Steps>
  <Step title="Navigate to API Keys">
    Go to **Project Admin → API Keys** in the nunu.ai dashboard
  </Step>

  <Step title="Create a new key">
    Click **Create API Key**
  </Step>

  <Step title="Select permissions">
    Choose the permissions your key needs based on your use case
  </Step>

  <Step title="Save your key">
    Copy and securely store your key—it won't be shown again
  </Step>
</Steps>

<Warning>
  API keys are sensitive credentials. Never commit them to version control or expose them in client-side code.
</Warning>

## Project Keys and Organization Keys

There are two kinds of API keys:

|            | Project API key              | Organization API key                                           |
| ---------- | ---------------------------- | -------------------------------------------------------------- |
| Created in | **Project Admin → API Keys** | **Org Admin → API Keys** (org admins only)                     |
| Key prefix | `nunu_`                      | `nunu_org_`                                                    |
| Scope      | One project                  | All projects of the organization                               |
| Works on   | All API routes               | Project scoped routes (`/api/v1/project/{projectId}/...`) only |

Organization keys are useful for tooling that spans multiple projects, such as a shared CI/CD pipeline. Because an organization key is not tied to a single project, every request made with one must name the project in the URL through the `/project/{projectId}` prefix. Requests to routes without that prefix are rejected with `401`.

## Using API Keys

Include your API key in the `X-Api-Key` header with every request:

```http theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
GET /api/v1/project/your-project-id/runs HTTP/1.1
Host: nunu.ai
X-Api-Key: YOUR_API_TOKEN
```

<CodeGroup>
  ```bash cURL theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  curl -X GET "https://nunu.ai/api/v1/project/your-project-id/runs" \
    -H "X-Api-Key: YOUR_API_TOKEN"
  ```

  ```typescript JavaScript/TypeScript theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  const response = await fetch("https://nunu.ai/api/v1/project/your-project-id/runs", {
    headers: {
      "X-Api-Key": process.env.NUNU_API_TOKEN,
    },
  });
  ```

  ```python Python theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  import requests
  import os

  response = requests.get(
      "https://nunu.ai/api/v1/project/your-project-id/runs",
      headers={"X-Api-Key": os.environ["NUNU_API_TOKEN"]}
  )
  ```
</CodeGroup>

## Permissions

API keys are scoped to specific permissions. Request only the permissions your integration needs:

| Permission                     | Description                               | Endpoints                                            |
| ------------------------------ | ----------------------------------------- | ---------------------------------------------------- |
| `project:read-runs`            | Read run data, artifacts, and bug reports | `GET /runs`, `GET /runs/{id}`, `GET /runs/{id}/bugs` |
| `project:operate-runs`         | Start and stop test runs                  | `POST /runs`, `POST /runs/stop`                      |
| `project:manage-build-storage` | Upload, manage, and delete builds         | All `/builds/*` endpoints                            |

### Combining Permissions

A single API key can have multiple permissions. For example, a CI/CD integration might need both `project:manage-build-storage` (to upload builds) and `project:operate-runs` (to trigger tests).

## Key Management Best Practices

### Use Environment Variables

Store API keys in environment variables, not in code:

```bash theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
# Set in your CI/CD environment or shell profile
export NUNU_API_TOKEN=your_token
export NUNU_PROJECT_ID=your_project_id
```

### Rotate Keys Regularly

<Steps>
  <Step title="Create new key">
    Create a new API key with the same permissions
  </Step>

  <Step title="Update integrations">
    Update all integrations with the new key
  </Step>

  <Step title="Deactivate old key">
    Deactivate the old key after confirming the transition works
  </Step>
</Steps>

### Use Separate Keys for Different Purposes

<AccordionGroup>
  <Accordion title="CI/CD Integration">
    Permissions: `project:manage-build-storage` + `project:operate-runs`

    Use for uploading builds and triggering tests from your CI/CD pipeline.
  </Accordion>

  <Accordion title="Monitoring Dashboard">
    Permissions: `project:read-runs` only

    Use for read-only access to view test results and run history.
  </Accordion>

  <Accordion title="Build Upload Only">
    Permissions: `project:manage-build-storage` only

    Use when you only need to upload builds without triggering tests.
  </Accordion>
</AccordionGroup>

### Monitor Key Usage

Check the **Last Used** timestamp in Project Admin → API Keys to identify unused keys that should be removed.

## Key Expiration

API keys can be configured with an expiration date. After expiration, requests with that key will receive a `403 Forbidden` response.

<Tip>
  To avoid disruption:

  * Set calendar reminders before key expiration
  * Create replacement keys in advance
  * Monitor for `403` errors in your integrations
</Tip>

## Error Responses

### Missing API Key (401)

```json theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
{
  "error": "API key required"
}
```

**Solution**: Include the `X-Api-Key` header in your request.

### Invalid API Key (401)

```json theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
{
  "error": "Invalid API key"
}
```

**Solution**: Verify your API key is correct and hasn't been deactivated.

### Expired API Key (403)

```json theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
{
  "error": "API key expired"
}
```

**Solution**: Create a new API key and update your integration.

### Disabled API Key (403)

```json theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
{
  "error": "API key is disabled"
}
```

**Solution**: Re-enable the key in Project Admin or create a new one.

### Missing Permission (403)

```json theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
{
  "error": "API key missing required permission: project:operate-runs"
}
```

**Solution**: Edit the API key to add the required permission, or create a new key with the needed permissions.

## Security Recommendations

<CardGroup cols={2}>
  <Card title="Server-Side Only" icon="server">
    API keys should only be used in server-side or CI/CD environments
  </Card>

  <Card title="HTTPS Only" icon="lock">
    All API requests must use HTTPS
  </Card>

  <Card title="Least Privilege" icon="shield">
    Grant only the permissions each integration needs
  </Card>

  <Card title="Regular Audits" icon="clipboard-check">
    Review and remove unused API keys regularly
  </Card>
</CardGroup>

<Info>
  In CI/CD, use your platform's secrets management (GitHub Secrets, GitLab CI Variables, Jenkins Credentials, etc.) to securely store API keys.
</Info>
