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

# API keys

> Mint a key, choose its permissions, and give it to the CLI once.

An API key identifies one caller. Every CLI command that reaches your factory uses a credential: an API key, or your own login. What a key does is attributed to that key. Give each machine a key of its own.

These are factory keys: each one works inside one factory. To manage the organization itself from a script, its members, roles and audit log, use a management API key. See [Organization API](/organization-api).

## Create a key

Open the factory, then **Settings → API keys**, and choose **Create API key**. Name it after what will use it, such as `laptop` or `ci`. The key is shown once, with a copy button. It is not shown again.

## Choose a preset

The dialog asks for a preset. Each preset is a fixed set of permissions, and **Custom** lets you tick them one by one.

<Frame caption="Four presets. Agent is the default and suits the CLI on a developer machine.">
  <img src="https://mintcdn.com/outer-layer/WamG4UDZsfczxWBI/images/api-key-role.png?fit=max&auto=format&n=WamG4UDZsfczxWBI&q=85&s=b5bac204da1c61eaf25f013b2f3b7dfe" alt="The preset dropdown with Agent, Runner, Reader and Custom" width="1448" height="876" data-path="images/api-key-role.png" />
</Frame>

| Preset | Carries | Use it for |
| - | - | - |
| **Agent** (`agent`) | `sessions.ingest`, `sessions.read`, `evidence.insert`, `work.read`, `work.insert`, `git.read`, `context.read` | The CLI on a developer machine. The default. |
| **Runner** (`runner`) | Everything Agent carries except `sessions.read` and `work.insert`, plus `work.update`, `work.claim` and `hosts.ingest` | An unattended runner claiming and working queued items. |
| **Reader** (`reader`) | Every read permission except `sessions.read_team`: `context.read`, `evidence.read`, `factory.read`, `factory_keys.read`, `git.read`, `hosts.read`, `metrics.read`, `sessions.read`, `work.read` | Dashboards and BI tools. It cannot mint or edit keys, and session actors come back anonymized. |
| **Custom** (`custom`) | Whatever you tick | Anything narrower. |

A preset's permissions are copied onto the key when it is made. A later change to a preset does not reach existing keys. Edit the key to add a missing permission.

<Frame caption="The Runner preset lists the permissions it carries.">
  <img src="https://mintcdn.com/outer-layer/WamG4UDZsfczxWBI/images/api-key-runner-preset.png?fit=max&auto=format&n=WamG4UDZsfczxWBI&q=85&s=e1ed695dcd11fa5921d7c5a877780b39" alt="The Create API key dialog with the Runner preset chosen and its permissions listed as chips" width="1200" height="740" data-path="images/api-key-runner-preset.png" />
</Frame>

The Agent preset covers every CLI command a developer runs, except `work remove` on someone else's addition. That needs `work.update`. The key the setup panel creates uses the Agent preset. To build a narrower key, pick **Custom** and tick what you need:

<Frame caption="Custom shows every permission, grouped by area.">
  <img src="https://mintcdn.com/outer-layer/WamG4UDZsfczxWBI/images/api-key-permissions.png?fit=max&auto=format&n=WamG4UDZsfczxWBI&q=85&s=810a0c3b4a42535ebeed1e9a90386e0b" alt="The Custom preset showing permission checkboxes grouped by area" width="1200" height="2072" data-path="images/api-key-permissions.png" />
</Frame>

| Permission | What it allows | Needed by |
| - | - | - |
| `sessions.ingest` | Upload agent sessions. | `sync` |
| `work.insert` | Add work, request a build, link a session and renew its claim, declare a pull request, remove your own addition. | `work build`, `work link-session`, `work pr`, `work open-pr` in your own session, `work remove` on your own addition |
| `work.read` | Look a work item up. | `work status`, `work list`, and `work remove` when you name the issue rather than the item number |
| `work.update` | Withdraw an addition somebody else recorded. | `work remove` on another caller's addition |
| `work.claim` | Claim, renew and release an item. | `work claim`, `work renew`, `work release`, `runner` |
| `evidence.insert` | Record a check, or emit an artifact, result or finding. | `emit` |

`work threads` needs `work.read`. `work comment` needs `work.insert`, `evidence.insert` or `work.review`, depending on what it records. See [`work comment`](/reference/cli-work#outerlayer-work-comment).

## Give the key to the CLI

```bash theme={"system"}
echo "$OUTERLAYER_KEY" | npx @outerlayer/cli login --url https://api.outerlayer.ai --app-id <factory-id>
```

The key is read from stdin when piped. It is never a command-line flag, so it never lands in shell history or process listings.

A piped key needs `--url https://api.outerlayer.ai`; there is no default. `--app-id` takes the **Factory Id**, which is on **Settings → General** with a copy button.

To sign in without a key, run `outerlayer login` with nothing piped and approve it in the dashboard. Then run `outerlayer connect` to choose a factory. The machine then holds a login for your account, not a key. A factory key always wins over a login, so CI and runners keep using theirs. See [Cloud commands](/reference/cli-cloud).

The dialog that reveals a new key shows this command with all three already filled in, so you can copy it from there. `login` writes `~/.outerlayer/config.json` with owner-only permissions.

## Use a key in CI

Set three environment variables instead of running `login`:

```bash theme={"system"}
OUTERLAYER_URL=https://api.outerlayer.ai
OUTERLAYER_API_KEY=<key>
OUTERLAYER_APP_ID=<factory-id>
```

Every command reads them before it reads the config file. See [Environment variables](/reference/environment-variables).

## Make your first API call

The Agent preset carries `work.read`, which listing work items needs. See [Make a request](/api-reference/introduction#make-a-request) for the call, and [Errors](/api-reference/introduction#errors) for what a refusal means.

## Rotate or revoke

Delete the key from **Settings → API keys**. Callers are refused within about five minutes, once the gateway's cached copy of it expires. Create a new key and run `login` again on each machine. `outerlayer mcp serve` reads the config when it starts, so your editor picks up a new key the next time it connects.

## Move a runner key to another host

A runner key, one that holds `work.claim`, is bound to the host key of the first machine that claims with it. The key then works only from that machine: the gateway refuses every request the host key did not sign. See [The host key](/run-a-host-as-a-service#the-host-key).

**Settings → API keys** shows each bound key's host key fingerprint and when it was bound. To move the key to a new machine, choose **Clear host key** on that row. You need permission to update API keys. The next claim from any machine binds that machine's host key, so clear the binding just before you start the runner on the new host. On an Enterprise plan, the organization audit log (**Settings → Audit log**) records each binding, each clearing, and each request the gateway refused for its signature.

## Limits

On OuterLayer Cloud, the Free and Growth plans allow 25 keys per organization, counted across every factory in it. Team and Enterprise have no limit.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.