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

# API keys

> Generate, scope, rotate, and revoke API keys for the Synheart Platform

API keys authorize calls into the Synheart Platform from the Synheart SDKs and your backend code. Keys are issued per-app, owned by an organization, and managed from the developer portal at [`platform.synheart.ai`](https://platform.synheart.ai).

<Note>
  The CLI uses OAuth Device Flow, not API keys, for `synheart login`. Generate an API key only when you need server-to-server or SDK-to-platform access. See [Authenticate the CLI](/setup/authenticate).
</Note>

## What a key carries

Each key the portal issues is bound to:

* An **organization** (selected from the org switcher).
* An **app** inside a [project](/platform/projects); keys are minted at the app level, so one key can't speak for multiple apps.
* A **label** you supply (free-form, used to identify the key in the list).
* One or more **scopes** that grant CRUD permissions: `read`, `write`, `delete`, `admin`.
* An **environment tag** for your own bookkeeping: `production`, `development`, `staging`, `testing`, or `other`.

## Generate a key

1. Open the developer portal and switch to the organization, tenant, and project that own the app.
2. Open the app's **API keys** tab and choose **Generate API Key**.
3. In the side panel, set:
   * **Choose App**: the key is bound to one app.
   * **Key Type**: `Production`, `Development`, `Staging`, `Testing`, or `Other`.
   * **Scopes**: tick at least one of `Read`, `Write`, `Delete`, `Admin`. The form blocks submission until one is selected.
4. The portal returns a **secret key** and a **signing secret** in a one-time dialog. Both are shown only once and stored hashed; copy them immediately into a secret manager. The dialog also offers a **Download credentials JSON** button that bundles the new secrets together with the identifiers: `org_id`, `tenant_id`, `project_id`, `app_id`, `secret_key`, and (when present) `signing_secret`. Save it to your secret manager; it never appears again.

The app detail page exposes a separate **credentials JSON** download that contains only the four identifiers (no secrets). Use that one for non-sensitive contexts (CI lookups, support tickets) and the one above for SDK / backend wiring. Use the secret key as `app_api_key` when configuring the runtime; see [Runtime configuration](/guides/runtime-config).

The two secrets serve different callers:

* **`secret_key`** authenticates every request via the `x-api-key` header. The on-device SDK uses this.
* **`signing_secret`** is for server-to-server callers that sign ingest requests directly from your own backend. The on-device SDK does **not** use this; it handles signing automatically. Only configure `signing_secret` if your backend bypasses the SDK and calls the platform REST API directly (e.g. from a server-side ingest pipeline).

## Ingestion access

Reading data and pushing biosignals share the same key surface, but **biosignal ingestion is gated by an app-level allowlist** maintained by Synheart. Keys for apps that aren't on the list are rejected at ingestion time with the message *"App `<app_id>` is not verified for data ingestion."*

If you need ingestion access, contact Synheart with the platform `app_id` shown on the App in the dashboard; there's no self-service request flow today.

## Rotate

There's no automatic rotation. To rotate:

1. Generate a new key with the same scopes and environment.
2. Roll both the secret key and signing secret out to your callers.
3. Revoke the old key.

## Revoke

Revoke unused keys from the API keys list. Revocation is immediate; subsequent requests with the revoked key fail with `401`. Revoked keys stay visible in the list (toggle **Include revoked**) for audit.

## Errors

| Status | Meaning                                                                                                                                      |
| ------ | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `401`  | Missing, malformed, or revoked key. Re-check that the `x-api-key` header is set and the key isn't revoked.                                   |
| `403`  | Key is valid but not authorized: either the app isn't allowlisted for ingestion, or the request body's `app_id` doesn't match the key's app. |
| `429`  | Rate limit exceeded. Back off and retry.                                                                                                     |

## Next

<Card title="Projects" icon="folder-tree" href="/platform/projects">
  Organize the apps your keys point at into projects.
</Card>
