---
title: Authentication
description: Create workspace API tokens, choose scopes and send them with every request.
---

# Authentication

Every API request needs a workspace API token. A token acts for its workspace: it sees and changes that workspace's monitors and spends that workspace's credit.

## Create a token

1. Sign in and open **Settings → API tokens**.
2. Name the token after what will use it, for example `deploy-bot` or `claude-agent`.
3. Choose its scope and, optionally, an expiry date.
4. Copy the token. It starts with `pgk_` and is **shown only once**; UpHeron stores only a hash of it.

You can have up to 50 active tokens per workspace. Revoke a token in the same place; it stops working immediately.

## Agents without a token: auth.md

An AI agent that supports [auth.md](/docs/auth-md) does not need a token from you. It registers at `https://upheron.com/agent/identity`, you type the 6-digit code it shows you, and it receives access tokens starting with `pga_` that last an hour and refresh themselves. They work exactly like API tokens with the `read` and `write` scopes. **Settings → Connected agents** lists these agents; disconnect one there. Agents read the details at [`/auth.md`](https://upheron.com/auth.md).

## Scopes

| Scope | Allows |
|---|---|
| `read` | Every `GET`: account, locations, monitors, results, incidents, payments, receipts |
| `write` | Everything `read` allows, plus creating, changing, pausing and deleting monitors, acknowledging incidents, and paying |

Give each agent the smallest scope it needs. An agent that only reports status should have a `read` token, which can never spend money.

## Send the token

Send the token in the `X-API-Key` header:

```bash
curl https://upheron.com/api/v1/account -H "X-API-Key: pgk_…"
```

`Authorization: Bearer pgk_…` also works for requests that do not carry a payment.

> **Use `X-API-Key` for anything that can be paid.** When an MPP client retries a paid request it puts its payment credential in the `Authorization` header (`Authorization: Payment …`), and a request can only have one `Authorization` header. `X-API-Key` keeps your token alongside it.

## Errors

| Status | `error` | Meaning |
|---|---|---|
| 401 | `missing_api_key` | No token was sent |
| 401 | `invalid_api_key` | The token is wrong or was revoked. An agent can get access itself with [auth.md](/docs/auth-md): the `WWW-Authenticate` header points to `https://upheron.com/.well-known/oauth-protected-resource` |
| 401 | `token_expired` | The token passed its expiry date |
| 403 | `insufficient_scope` | The request needs the `write` scope |
| 429 | `rate_limited` | Too many requests or failed sign-ins; wait for `Retry-After` seconds |

Repeated failed authentication from one IP address is rate limited, so tokens cannot be guessed.

## Keep tokens safe

- Store tokens in your agent's secret store or environment, never in code or prompts that are logged.
- Use one token per agent or integration, so you can revoke one without breaking the others.
- Set an expiry date on tokens for experiments.
- Tokens are not tied to an IP address; anyone with the token can use it. Revoke a token you think has leaked.
