---
title: Authentication and scopes
description: How API keys work, the two scopes, and what each request is allowed to do.
order: 2
---

## Key format

A key looks like `hpk_` followed by 64 hex characters (32 bytes of randomness) - the same entropy
budget HeimPulse uses for its own session ids. Send it as a bearer token:

```
Authorization: Bearer hpk_...
```

Keys are hashed (SHA-256) at rest. HeimPulse cannot look up, recover, or re-display a key's
plaintext after the moment it's created - if you lose it, revoke it and mint a new one.

## Scopes

Every key has exactly one scope, chosen at creation:

- **`read_write`** (the default) - can read and mutate anything the API surface allows.
- **`read_only`** - every `GET` still works; any `POST`/`PATCH`/`DELETE` is rejected with `403`.

There's no finer-grained, per-resource permission model today (e.g. "services only, not
incidents") - if you need that separation, mint separate keys per integration and give each only
the scope it needs.

## What a key can see

A key is scoped to exactly the org it was minted in. There is no `{org_id}` in any `/v1` URL - the
org is entirely implied by which key authenticated the request, so a key can never be pointed at
another org's data by editing a URL.

## What a key can't do

API keys are deliberately narrow. They cannot:

- Manage billing or change the org's plan.
- Invite, remove, or manage org members.
- Manage other API keys (minting/revoking keys is dashboard-only, owner-gated - the same reason a
  Stripe or GitHub token can't mint other tokens through the API it itself authenticates).
- Read or configure notification channels (webhooks/Slack/email).
- Touch anything outside `/v1` - the session-cookie-authenticated dashboard API is a separate
  surface entirely.

See [API keys vs. webhooks](/guides/api-keys-vs-webhooks) if you're trying to decide which
mechanism fits what you're building.
