Skip to main content
An API key (hk_…) lets a system with no browser call the same admin API the console uses, and the hosted MCP server at /mcp: a CI job, an infrastructure-as-code tool, a nightly script or your own backend. For a coding agent working with you interactively, connect it over OAuth instead. A key is not a user of its own. It acts as the member who created it, and its role is a ceiling on that member’s role. So a key can never do more than its creator can do in the console, and it follows its creator: demote the creator and the key is demoted with them; remove them from the workspace and the key stops working.

Create a key

1

Open Settings → API keys

In the console, open Settings → API keys. Owners and admins manage keys; other members see who to ask.
2

Create it

Choose Create API key and fill in:
  • Name: the system that will use it, such as GitHub Actions deploy, so you know what to revoke later.
  • Role: viewer, developer or admin. See Roles.
  • Projects: All projects, or one project. See Project scope.
  • Expires: in 90 days (the default), 30 days, 7 days, 1 year, or never.
  • Allowed source IPs (optional): the addresses the key may be used from.
3

Copy it now

The key is shown once. Hookie stores only a SHA-256 hash of the whole key and looks it up by that hash; the list shows the first 11 characters (hk_ and 8 more) from then on. Store it in your CI system’s secret store.
Only a person signed in to the console can create a key. A connected agent, or another API key, is refused, so one leaked or over-granted credential cannot mint more. You cannot create a key with a higher role than your own. While the workspace is suspended, creating a key is refused but revoking one still works. Creating and revoking a key are recorded in Settings → Audit log (create_api_key, revoke_api_key). Every change a key makes is recorded as its creator, with the key named as the agent (api_key:<id>).

Roles

There is no owner role for a key, so billing is never reachable with one. Like a connected agent, a key also cannot reveal or rotate a destination’s signing secret, manage connected agents, or create API keys. Those stay with a person in the console. The role is applied on every request against the creator’s role at that moment. A developer key made by an admin who is later made a viewer can only read.

Project scope

A key for one project reaches:
  • /admin/api/projects/{its project id}/…
  • /admin/api/me
  • the destination and source presets
Everything else answers 403 and names the routes the key can use. That includes the project list (it would name the other projects), other projects, the Default-project shortcuts such as /admin/api/rules, and workspace-wide routes such as members, SSO and the audit log. A key for all projects reaches whatever its role allows across the workspace.

Expiry and IP allowlist

An expired key is refused with 401, exactly like a revoked one. Over the API, expires_at is an ISO 8601 time in the future. Leave it out, or send null, for a key that never expires. A key’s allowed source IPs hold up to 64 IPv4 or IPv6 addresses or CIDR ranges. A request from any other address is refused with 403; on /admin/api the refusal is recorded in the audit log as access_denied. A key with an allowlist is refused when the request’s source address cannot be determined. An empty list accepts any address. The list shows each key’s role, project, expiry, allowed IPs, creator, when it was created and when it was last used, with a status of active, expired or revoked. Last used is updated at most once a minute.

Use a key

Send it as a bearer token:
A write made with a bearer token needs no CSRF header; that check applies only to the console’s session cookie. GET /admin/api/me names the key the request was made with under api_key (id, and project_id for a key scoped to one project). The hosted MCP server accepts a key the same way, so an MCP client that cannot run the OAuth flow can send one as a header. The key’s role decides which tools it can call: a viewer key reaches the hookie:read tools, a developer key also the hookie:write ones, and an admin key the hookie:manage ones too.
Never commit a key. Reference it from an environment variable, as above, and keep the value in your secret store.

Rate limits

Each credential may make 100 requests every 10 seconds to /admin/api and /mcp combined. Each API key, each connected agent and each person signed in to the console is counted separately, so one runaway script cannot lock out the rest of your team. Over the limit, the request is refused with 429 and a Retry-After: 10 header. On /admin/api the body is:
On /mcp the same 429 and Retry-After carry a JSON-RPC error (code -32029). Wait the number of seconds in Retry-After, then retry.

Idempotent retries

Send an Idempotency-Key header on a POST to /admin/api, and a retry of that request is answered once, not run twice. Use a new unique value, such as a UUID, for each distinct request, and the same value when you retry it.
  • The first request runs, and its response is stored, encrypted, for 24 hours.
  • A retry with the same key, from the same credential, to the same path with the same body gets the stored response back with Idempotent-Replayed: true. Nothing runs again.
  • The same key with a different body, path or credential is refused with 422. Use a new key for a new request.
  • A retry that arrives while the first request is still running gets 409 with Retry-After: 1. A request still unfinished after 60 seconds is treated as abandoned, and its key is free again.
  • A server error (5xx) is not stored, so you can retry with the same key. An error in the 4xx range is stored and replayed like a success.
The key is 1 to 255 printable characters with no spaces; anything else is 400. It is ignored on methods other than POST. A response larger than 64 KiB, or one that is not JSON, is not stored. A workspace can hold 10,000 keys in any 24 hours; past that, a request with a new key is refused with 429 and Retry-After: 3600. POST /admin/api/api-keys refuses the header with 400: its response is a key that is shown once, and a stored copy would be a second way to recover it.

Versioning

Every response from /admin/api and /mcp carries the API version, errors and 429s included:
Additive changes (a new route, a new response field, a new optional parameter) ship under the current version, so ignore fields you do not recognise. A breaking change gets a new dated version, and the previous version stays available for at least 12 months. To pin a version, send it as a Hookie-Version request header. A version this deployment does not serve is refused with 400, and the body lists supported_versions. Today that is 2026-09-29 only.

Revoke a key

Choose Revoke on the key’s row and confirm. Its next request is refused with 401. Keys cannot be edited or rotated: to change a key’s role, project, expiry or allowlist, create a new one, move your system over, then revoke the old one.

API

Owners and admins, or an admin-role credential:
role is viewer, developer or admin. project_id is a project’s id, or null for every project. The 201 response carries the key once, in key, with Cache-Control: no-store. Only a person signed in to the console can create a key; see Create a key. The full contract is in the API reference.