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

# Authentication

Every request to the Pivotal API carries an API key in the `Authorization` header:

```
Authorization: Bearer pivotal_K8s9X2mPq…
```

Keys are created from [Admin > API Keys](https://my.pivotal.app/admin/api-keys) inside the workspace they should access. There is no OAuth flow, no exchange step, and no signed request scheme — Bearer auth over TLS is the entire mechanism.

## Key formats

| Prefix           | Mode | What it does                                                                                                                                                                      |
| ---------------- | ---- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `pivotal_…`      | Live | Mutates production state, fires webhooks, sends real emails and Slack notifications via configured integrations.                                                                  |
| `pivotal_test_…` | Test | Mutates production state, but suppresses outbound integration side effects (Slack, Resend, Stripe). Sits on a separate rate-limit bucket. See [Test mode](/api/guides/test-mode). |

The cleartext key is shown exactly once — at create time, in a copy-able banner. Pivotal stores only a PBKDF2-SHA256 hash. Lose the key and you have to create a new one.

The visible **key prefix** (e.g. `pivotal_K8s9`) is safe to log and appears on the API Keys page so you can match revoked keys to deployments. The remaining bytes are the secret half.

## Sending the key

```bash title="curl"
curl https://my.pivotal.app/api/v1/me \
  -H "Authorization: Bearer $PIVOTAL_API_KEY"
```

```typescript title="Node"
const res = await fetch("https://my.pivotal.app/api/v1/me", {
  headers: { Authorization: `Bearer ${process.env.PIVOTAL_API_KEY}` },
});
```

```python title="Python"
import os, requests
res = requests.get(
    "https://my.pivotal.app/api/v1/me",
    headers={"Authorization": f"Bearer {os.environ['PIVOTAL_API_KEY']}"},
)
```

Common header mistakes that return `401`:

* Missing `Bearer` prefix (`Authorization: pivotal_…`)
* Extra colon (`Bearer: pivotal_…`)
* Lowercase `bearer` — Pivotal accepts it, but some intermediaries strip it
* Trailing whitespace from a copy/paste

## Scope

Every key is scoped to exactly one workspace (one Pivotal "org"). A key for the `vml` workspace cannot read or write data in the `aurora` workspace, and vice versa. There is no cross-workspace key.

Inside a workspace, a key carries **full read/write** across all resources. There is no per-endpoint or per-resource scoping yet. Treat any key like a workspace admin password.

## Rotation

Pivotal supports concurrent active keys so rotation is zero-downtime:

1. Create a new key in [Admin > API Keys](https://my.pivotal.app/admin/api-keys).
2. Roll it out to your servers (env var swap + restart).
3. Confirm the old key's last-used time stops advancing.
4. Click **Revoke** on the old key.

A revoked key returns `401 authentication_error / api_key_revoked` instantly on the next request — there is no grace period.

## Storing keys

Don't:

* Commit keys to git, even in a private repo.
* Send keys in URL query strings (`?api_key=…`). The header is the only supported transport, and URL params end up in access logs and referer headers.
* Embed keys in browser code. The API is server-to-server; a key in front-end JS hands the workspace to anyone who opens DevTools.

Do:

* Inject keys at runtime from your secret manager (Vault, AWS Secrets Manager, Doppler, 1Password CLI).
* Use a different key per environment (`dev`, `staging`, `prod`) so revoking one is surgical.
* Use a different key per service when you can — the API Keys page shows last-used timestamps, which makes blast-radius investigation faster after an incident.

## Detecting compromise

Each key's row shows **last used at**, **last used IP** (where available), and **request count**. Anything unexpected — a key marked "ci" hitting from a random VPS, a "local-dev" key still active after the laptop was sold — is a signal to revoke.

If a key leaks, revoke first, investigate second. Revoke is one click and reversible (you can re-create a key with the same name); waiting to revoke while you investigate is not.

## Webhooks (preview)

Outbound webhooks are not yet part of the public API. The placeholder page at [Webhooks](/api/welcome/webhooks) describes the planned shape. For now, poll the relevant list endpoints with `?cursor=` to stay in sync.