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

# Authentication

> Create API keys, use the right auth header for each API, and authenticate the CLI.

Moda uses one credential for data access — the API key — plus a browser-based CLI session for CLI setup commands. This page covers creating and revoking keys, the header each API expects, and CLI authentication for interactive and headless use.

## API keys

API keys (called ingestion keys in the dashboard) authenticate both the Ingestion API and the Data API.

<Steps>
  <Step title="Open Settings → Ingestion keys">
    Creating and revoking keys requires the admin or owner role. All members can view the key list.
  </Step>

  <Step title="Create a key">
    Click **New ingestion key** and name it.
  </Step>

  <Step title="Copy the key now">
    The full key is shown once, at creation. Afterwards the list shows only the key's name, prefix, creation date, and last-used date.
  </Step>
</Steps>

Keys start with `moda_sk_` and are bound to the workspace they were created in. A key cannot be moved or re-pointed to another workspace — the server derives the workspace from the key on every request.

## Which header to use

The two APIs read different headers. Sending the wrong one returns `401`.

| API           | Base URL                                | Auth header                         |
| ------------- | --------------------------------------- | ----------------------------------- |
| Ingestion API | `https://moda-ingest.modas.workers.dev` | `Authorization: Bearer moda_sk_...` |
| Data API      | `https://moda.dev/api/v1/data`          | `x-api-key: moda_sk_...`            |

<Note>
  The Ingestion API also accepts the bare key in the `Authorization` header, without the `Bearer ` prefix.
</Note>

Ingestion API example:

```bash theme={"dark"}
curl -X POST https://moda-ingest.modas.workers.dev/v1/ingest \
  -H "Authorization: Bearer YOUR_MODA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"events":[{"conversation_id":"conv_123","role":"user","message":"Hello"}]}'
```

```json theme={"dark"}
{ "success": true, "count": 1, "requestId": "7f9b2c9e-0a41-4c3e-9f1a-2d5c8e7b6a90" }
```

A missing header returns `401` with `{"success": false, "count": 0, "message": "Missing Authorization header", "requestId": "..."}`; a revoked or malformed key returns `401` with `"Invalid or expired API key"`.

Data API example:

```bash theme={"dark"}
curl "https://moda.dev/api/v1/data/tool-failures?days_back=7" \
  -H "x-api-key: YOUR_MODA_API_KEY"
```

```json theme={"dark"}
{
  "summary": {
    "total": 42,
    "total_calls": 1875,
    "conversations": 31,
    "tools": 3,
    "failure_rate_pct": 2.2
  },
  "tools": [
    {
      "tool_name": "search_flights",
      "failure_count": 28,
      "total_count": 640,
      "failure_rate_pct": 4.4,
      "conversation_count": 22,
      "top_error": "Upstream timeout after 10s",
      "last_seen": "2026-08-15T21:04:11Z"
    }
  ]
}
```

In the SDKs, the Python SDK's `moda.init()` reads the `MODA_API_KEY` environment variable; the Node.js SDK's `Moda.init(apiKey, options)` requires the key as an explicit argument. See [Python](/ingestion/python) and [Node.js](/ingestion/node).

## Revoking a key

Revoke keys in **Settings → Ingestion keys** (admin or owner role).

<Warning>
  The Ingestion API caches key-validation results for up to 60 seconds, so a revoked key can continue to ingest for up to a minute after revocation. To rotate without data loss, create the new key, deploy it everywhere, then revoke the old one.
</Warning>

## CLI authentication

The CLI uses two credentials:

* **CLI session** — `moda auth login` opens the browser; signing in creates a CLI session used by setup and control commands such as `moda init` and `moda provision`. `moda auth status` shows the current session (exit code 4 when logged out); `moda auth logout` revokes it.
* **API key** — Data API commands (`moda search`, `moda overview`, `moda emotions`, `moda problem`, `moda tail`, ...) use an API key, not the session; this includes the write command `moda problem-feedback`. The CLI resolves the key in this order: the `MODA_API_KEY` environment variable, then the active profile, then `~/.moda/config.json`.

### Headless and CI: `moda provision`

`moda provision` mints (or reuses) a workspace API key without any prompts and prints exactly one JSON document to stdout:

```json theme={"dark"}
{
  "apiKey": "moda_sk_...",
  "tenantId": "…",
  "tenantName": "…",
  "tenantSlug": "…",
  "ingestUrl": "https://moda-ingest.modas.workers.dev",
  "baseUrl": "https://moda.dev",
  "reused": false
}
```

It requires an existing CLI session and never opens a browser — run `moda auth login` on a machine with a browser first, then provision. Typical use for CI is provisioning locally and storing the key as a CI secret:

```bash theme={"dark"}
moda auth login
MODA_API_KEY="$(moda provision | jq -r .apiKey)"
```

Behavior:

* Exit code 4 when no CLI session exists.
* Exit code 5 when your account belongs to multiple workspaces and neither `--tenant-id` nor `MODA_TENANT_ID` selects one.
* `--label` names the key (defaults to the hostname); `--save` persists the credentials to `~/.moda/config.json`; `reused: true` means an existing key was returned instead of a new one.

## Next steps

* [Ingestion overview](/ingestion/overview) — where the Bearer header is used.
* [Data API overview](/data-api/overview) — where the `x-api-key` header is used.
* [Team](/administration/team) — the roles that gate key creation and revocation.
* [Limits](/administration/limits) — request and query limits across both APIs.
