> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.runtype.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.runtype.com/_mcp/server.

# Authentication

> How to authenticate with the Runtype API

The Runtype API uses API keys to authenticate requests. Include your API key in the `Authorization` header of every authenticated request.

## Before you begin

Sign in to the [Runtype Dashboard](https://use.runtype.com). You need a Runtype account to create an API key.

## Create an API key

An API key belongs to the organization that's active in the dashboard when you create it. If you belong to more than one organization, switch to the correct one first.

Create an API key in the dashboard by following these steps:

1. On the **Settings > API** page, click **Create New API Key**.
2. Enter a descriptive name for the key.
3. Select **Test** or **Production** as the environment.
4. Select the permissions that your application needs.
5. Optional: Set an **Expiration Date**.
6. Click **Create API Key**. The success dialog opens.
7. Copy the key from the success dialog. You can't view a Production key again. You can reveal an active Test key that you created.

You create, edit, reveal, regenerate, and delete API keys in the dashboard. The API rejects these requests when they use another API key. For key ownership and admin views, see [Managing API keys](/user-guide/settings/managing-api-keys).

> **Warning**
>
> Store API keys securely. Don't expose them in client-side code or commit them to version control.
> For browser or embedded use, create a [client token](/user-guide/products-surfaces/client-tokens-and-domain-restrictions) instead.

## Use your API key

Send the API key in the `Authorization` header with the `Bearer` scheme:

#### cURL

**`cURL`**

```bash title="cURL"
curl https://api.runtype.com/v1/flows \
  -H "Authorization: Bearer $RUNTYPE_API_KEY"
```

#### TypeScript SDK

**`TypeScript`**

```typescript title="TypeScript"
import { RuntypeClient } from '@runtypelabs/sdk'

const client = new RuntypeClient({
  apiKey: process.env.RUNTYPE_API_KEY,
})

const flows = await client.flows.list()
```

The SDK doesn't read `RUNTYPE_API_KEY` by itself. Pass the key in `apiKey`, or call `client.setApiKey()`.

#### CLI

**`CLI`**

```bash title="CLI"
runtype login                        # Sign in through the browser.
runtype login --api-key YOUR_API_KEY # Sign in with an existing API key.
```

Replace `YOUR_API_KEY` with your Runtype API key. The CLI checks the `RUNTYPE_API_KEY` environment variable before its stored credentials.

These examples read the key from the `RUNTYPE_API_KEY` environment variable. To set it, run `export RUNTYPE_API_KEY="YOUR_API_KEY"`.

### Verify your key

To confirm that a key works and see the account that it belongs to, call `GET /v1/auth/me`:

**`cURL`**

```bash title="cURL"
curl https://api.runtype.com/v1/auth/me \
  -H "Authorization: Bearer $RUNTYPE_API_KEY"
```

A valid key returns `200` with the `userId` and `orgId` of the key. This endpoint doesn't need a specific permission, so a `401` here means that the key itself isn't valid. In the CLI, run `runtype auth whoami`.

## API key formats

Runtype uses the following API key prefixes:

| Prefix     | Environment | Description                                                       |
| ---------- | ----------- | ----------------------------------------------------------------- |
| `rt_live_` | Production  | Uses all the permissions that you assign.                         |
| `rt_test_` | Test        | Uses the permissions that you assign, with Test key restrictions. |

Test keys support a fixed subset of scopes. They can't use the `*` scope, delete resources, or manage API keys, integrations, or schedules. Each Test key can run 20 executions per day and 200 over its lifetime. For what happens at a limit, see [Test key limits](#test-key-limits).

## Permissions

Use permissions to limit what an API key can do. The following table lists common scopes:

| Permission        | Description                                                                                                         |
| ----------------- | ------------------------------------------------------------------------------------------------------------------- |
| `*`               | Full access to all resources.                                                                                       |
| `DISPATCH:*`      | Execute Flows with Records through the dispatch API.                                                                |
| `FLOWS:*`         | Full access to Flows.                                                                                               |
| `FLOWS:READ`      | Read Flows.                                                                                                         |
| `FLOWS:WRITE`     | Create and update Flows. Deleting a Flow requires `FLOWS:*`.                                                        |
| `FLOWS:EXECUTE`   | Execute Flows.                                                                                                      |
| `RECORDS:*`       | Full access to Records.                                                                                             |
| `RECORDS:READ`    | Read Records.                                                                                                       |
| `RECORDS:WRITE`   | Create and update Records. Deleting a Record requires `RECORDS:*`.                                                  |
| `PROMPTS:*`       | Full access to Prompts.                                                                                             |
| `AGENTS:*`        | Full access to Agents.                                                                                              |
| `AGENTS:READ`     | Read Agents.                                                                                                        |
| `AGENTS:WRITE`    | Create and update Agents.                                                                                           |
| `AGENTS:EXECUTE`  | Execute Agents.                                                                                                     |
| `PRODUCTS:READ`   | Read Products and their configuration.                                                                              |
| `PRODUCTS:WRITE`  | Create and update Products.                                                                                         |
| `EVALS:*`         | Full access to Evals.                                                                                               |
| `EVALS:READ`      | Read Evals and cases.                                                                                               |
| `EVALS:WRITE`     | Create, update, and delete Evals and cases, including from [evals as code](/user-guide/evals/manage-evals-as-code). |
| `TOOLS:*`         | Full access to Tools and Model Context Protocol (MCP) tools.                                                        |
| `APPS:*`          | Full access to Apps.                                                                                                |
| `APPS:READ`       | Read Apps and versions.                                                                                             |
| `APPS:WRITE`      | Create, deploy, activate, and delete Apps. This permission includes read access.                                    |
| `ANALYTICS:READ`  | Read analytics data.                                                                                                |
| `TELEMETRY:*`     | Full access to telemetry ingest.                                                                                    |
| `SIGNALS:READ`    | Read signal sets, bindings, and signal stats.                                                                       |
| `SIGNALS:WRITE`   | Create, preview, bind, and unbind signal sets. Includes read access.                                                |
| `TELEMETRY:WRITE` | Send traces, runs, and runtime telemetry to Runtype. This permission doesn't grant read or management access.       |
| `RUNTIME:EXECUTE` | Call the hosted endpoints that a self-hosted runtime uses, such as the platform-key proxy and memory.               |

To view all available scopes and permission groups, open the **Settings > API** page and create or edit a key. For more information, see [Managing API keys](/user-guide/settings/managing-api-keys).

Use `TELEMETRY:WRITE` for collectors, containers, continuous integration (CI) jobs, and other instrumented services. This append-only scope grants ingest access without read or management access. Select the **Telemetry Ingest** permission group to create a key with this scope. For setup instructions, see [Reporting telemetry from an external agent](/developer-guides/guides/reporting-external-telemetry).

## Agent self-registration (anonymous start)

If your agent needs an API key before a person creates one, use anonymous-start registration. The agent receives a scoped pre-claim key and can bind it to an email address later. For the protocol specification, see [the `auth.md` anonymous-start pattern](https://runtype.com/auth.md).

### Prefer the CLI

Use the `runtype` CLI for a non-interactive registration flow without a browser:

**`CLI`**

```bash title="CLI"
runtype auth register --email dana@example.com  # Register and send the one-time code.
runtype auth verify YOUR_OTP                    # Complete the claim with the code.
runtype auth claim dana@example.com             # Resend or change the email address.
```

Replace `YOUR_OTP` with the six-digit code from the email.

The `runtype` CLI stores the resulting credential for subsequent CLI commands. Each command prints JSON with a `next` field that identifies the next step. Use the HTTP protocol when you can't install `@runtypelabs/cli`.

### Discovery

Find the registration flow through either of these discovery signals:

* A `WWW-Authenticate` header on a `401` response identifies the protected-resource metadata URL.
* The `agent_auth` block in `GET /.well-known/oauth-authorization-server` lists the registration endpoints. The `auth.md` specification describes the protocol.

### Register anonymously

The registration and claim endpoints are unauthenticated. The claim token authenticates the claim requests.

Send a `POST` request to `/agent/auth` to receive a pre-claim API key and claim token:

**`cURL`**

```bash title="cURL"
curl -X POST https://api.runtype.com/agent/auth \
  -H "Content-Type: application/json" \
  -d '{ "type": "anonymous", "requested_credential_type": "api_key" }'
```

The API returns `201` with the pre-claim key in `credential` and the claim token in `claim_token`:

**`201 response (abridged)`**

```json title="201 response (abridged)"
{
  "registration_id": "REGISTRATION_ID",
  "credential": "rt_live_PRE_CLAIM_KEY",
  "credential_expires": "2026-09-28T12:00:00.000Z",
  "claim_url": "https://api.runtype.com/agent/auth/claim",
  "claim_token": "CLAIM_TOKEN",
  "claim_token_expires": "2026-09-28T12:00:00.000Z"
}
```

The response also lists the key's `scopes` and the `post_claim_scopes` that the claimed key receives. The pre-claim key and the claim token each expire after 24 hours. If the pre-claim key expires before you complete the claim, the claim fails with `410` and `credential_expired`, and you must register again.

The pre-claim key is an `rt_live_` key with these scopes:

* `FLOWS:READ` and `FLOWS:WRITE`.
* `AGENTS:READ` and `AGENTS:WRITE`.
* `RECORDS:READ`, `TOOLS:READ`, and `ANALYTICS:READ`.
* `PRODUCTS:READ`, `PRODUCTS:WRITE`, `PRODUCTS:CREATE`, and `PRODUCTS:UPDATE`.
* `PRODUCTS:SURFACES:READ` and `PRODUCTS:CAPABILITIES:READ`.

It doesn't include `DISPATCH:*`, execute scopes, `RECORDS:WRITE`, or tool execution. It also excludes `SECRETS:*`, API-key management, integrations, schedules, webhooks, messaging, agent-to-agent (`A2A`) scopes, and delete permissions.

### Claim the registration

To replace the pre-claim key with a full-access key, send the claim token and your email address to `/agent/auth/claim`:

**`Initiate claim`**

```bash title="Initiate claim"
curl -X POST https://api.runtype.com/agent/auth/claim \
  -H "Content-Type: application/json" \
  -d '{ "claim_token": "YOUR_CLAIM_TOKEN", "email": "dana@example.com" }'
```

Replace `YOUR_CLAIM_TOKEN` with the `claim_token` that registration returns.

This request sends a one-time code to your email address. Complete the claim by sending that code to `/agent/auth/claim/complete`:

**`Complete claim`**

```bash title="Complete claim"
curl -X POST https://api.runtype.com/agent/auth/claim/complete \
  -H "Content-Type: application/json" \
  -d '{ "claim_token": "YOUR_CLAIM_TOKEN", "otp": "YOUR_OTP" }'
```

Use the same `YOUR_CLAIM_TOKEN` value and replace `YOUR_OTP` with the code from the email.

After successful verification, Runtype revokes the pre-claim key and issues a new full-access `rt_live_` key (scope `*`) bound to your account.

> **Note**
>
> One-time codes expire after 10 minutes. After 5 failed attempts, Runtype locks the claim and
> revokes the pre-claim key. Registration requests are limited to 5 attempts per hour per IP
> address.

## Agent registration with an identity assertion (ID-JAG)

If your agent has an ID-JAG (Identity Assertion JWT Authorization Grant) from a trusted agent identity provider, register it with one request. Runtype validates the short-lived JWT and issues a full-access key for a new account tied to the verified email. This flow doesn't use a pre-claim key or an email one-time code.

**`cURL`**

```bash title="cURL"
curl -X POST https://api.runtype.com/agent/auth \
  -H "Content-Type: application/json" \
  -d '{
    "type": "identity_assertion",
    "assertion_type": "urn:ietf:params:oauth:token-type:id-jag",
    "assertion": "YOUR_ID_JAG_JWT",
    "requested_credential_type": "api_key"
  }'
```

Replace `YOUR_ID_JAG_JWT` with the JWT from your identity provider.

The assertion must meet these requirements:

* A trusted agent identity provider issues it. Runtype accepts `https://auth.workos.bot` (WorkOS).
* Its audience is `https://api.runtype.com/agent/auth` or `https://api.runtype.com`.
* It contains a verified email claim: `email` and `email_verified: true`.
* It contains `sub` and `exp` claims.
* It contains a `jti` claim. Runtype accepts each assertion once and rejects assertions older than 10 minutes.

On success, the response includes `status: "claimed"` and a full-access `rt_live_` key. If the email already belongs to a Runtype account, Runtype returns `email_already_registered`. Sign in to the dashboard and create an API key instead. The `identity_assertion` and `anonymous` identity types appear in the `agent_auth` block of `GET /.well-known/oauth-authorization-server`.

## Rate limits

Plans don't cap the total number of Flow executions. Some plans have a **burst rate**, which limits how many Flow executions you can start in a 10-second window. If your plan has a burst rate and you exceed it, the API returns `429` with a `Retry-After` header. If your plan has no burst rate, this check doesn't apply.

Spending controls return `402` instead of `429`. For more information, see [Rate limits and usage](/user-guide/troubleshooting-faq/rate-limits-and-usage).

When a burst rate applies, execution responses include headers like these:

**`Rate limit headers`**

```http title="Rate limit headers"
RateLimit-Limit: 50
RateLimit-Remaining: 49
RateLimit-Reset: 5
```

`RateLimit-Limit` is your plan's burst rate for each 10-second window. `RateLimit-Remaining` and `RateLimit-Reset` are fixed estimates that don't change with each request. Use a `429` response and its `Retry-After` header as the signal to slow down.

## Error responses

These examples show common authentication and rate-limit errors.

### 401 Unauthorized

The API returns `401` when a request lacks a valid API key:

**`401 response`**

```json title="401 response"
{
  "error": "Unauthorized"
}
```

The body is the same for every cause. Common causes include these:

* The `Authorization` header is missing or doesn't use the `Bearer` scheme.
* The key passed its expiration date.
* Someone deactivated or deleted the key.
* Someone regenerated the key, which makes the previous value stop working.
* The key's owner left the organization. Runtype revokes that person's keys in the organization.

For more troubleshooting steps, see [Authentication issues](/user-guide/troubleshooting-faq/authentication-issues).

### 403 Forbidden

The API returns `403` when an API key lacks a required permission. The message usually names the scope to add:

**`403 response`**

```json title="403 response"
{
  "error": "Insufficient permissions. Required: FLOWS:READ or FLOWS:*"
}
```

### 429 Too many requests

The API returns `429` when a request exceeds a burst rate. Branch on the `code` field, not on the `error` text:

**`429 response (abridged)`**

```json title="429 response (abridged)"
{
  "error": "Limit Exceeded",
  "message": "Rate limit exceeded. Please retry after 5 second(s).",
  "code": "RATE_LIMIT_EXCEEDED",
  "limitType": "rate"
}
```

The response also includes `upgradeUrl`, `resetsAt`, and `stats`.

### Test key limits

When a Test key reaches its daily or lifetime limit, execution requests return `429` with a Test key body:

**`429 response for a Test key (abridged)`**

```json title="429 response for a Test key (abridged)"
{
  "error": "Test Key Limit Exceeded",
  "code": "TEST_KEY_DAILY_LIMIT_EXCEEDED",
  "limitType": "daily",
  "upgradeMessage": "Create a live API key for unlimited access."
}
```

The `code` is `TEST_KEY_DAILY_LIMIT_EXCEEDED` or `TEST_KEY_LIFETIME_LIMIT_EXCEEDED`. The response also includes `message`, `upgradeUrl`, `resetTime`, and `stats`.

Successful execution responses for a Test key include these headers:

* `X-Test-Key-Remaining-Daily` and `X-Test-Key-Limit-Daily`.
* `X-Test-Key-Remaining-Lifetime` and `X-Test-Key-Limit-Lifetime`.

Some operations that Test keys can't perform return `403` with `code: "TEST_KEY_PERMISSION_DENIED"` and an `upgradeUrl`. When you reach a limit or a restriction, create a Production key.

### 503 Service unavailable

The API returns `503` when Runtype can't verify a credential for a short time:

**`503 response`**

```json title="503 response"
{
  "error": "Credential verification is temporarily unavailable"
}
```

This response is temporary and doesn't mean that your key is invalid. Retry the request after the number of seconds in the `Retry-After` header.

## Best practices

Use these practices to manage your API keys:

#### Use environment variables

Store API keys in environment variables instead of source code:

**`Shell`**

```bash title="Shell"
export RUNTYPE_API_KEY="YOUR_API_KEY"
```

Replace `YOUR_API_KEY` with your Runtype API key.

#### Use scoped permissions

Grant each application only the permissions it needs. A read-only key doesn't need write permissions.

#### Rotate keys regularly

Rotate API keys on a schedule. To force rotation, set an **Expiration Date** when you create a key.

You can rotate a key in two ways:

* [Regenerate the key](/user-guide/settings/managing-api-keys#regenerate-an-api-key). It keeps its name, permissions, and expiration, and the previous value stops working immediately. Use this option when you can update every client at once.
* Create a second key, deploy it to your applications, and then delete the old key. Use this option to rotate without downtime.

#### Monitor usage

Review the **Settings > API** page in the dashboard to identify unusual activity.

## Next steps

Continue with these guides:

#### [Quickstart](/developer-guides/getting-started/quickstart)

Make your first authenticated API call.

#### [Managing API keys](/user-guide/settings/managing-api-keys)

Regenerate, delete, and review API keys.

#### [Product API keys](/user-guide/products-surfaces/authenticating-with-product-api-keys)

Authenticate callers of a Product Surface.

#### [API Reference](/api-reference/overview)

Explore the available endpoints.

#### [API error reference](/user-guide/troubleshooting-faq/api-error-reference)

Look up error codes and limit responses.