Authentication

Bearer Header

Include your API key as a Bearer token in the Authorization header on every request:

header
Authorization: Bearer hb_adm_xxxxx...

API Key Types

Headband has two key types, admin and search. A project-scoped key works on one branch of one project (the project's default keys are for its main branch). An org-scoped key works across every project in your organization and is always an admin key. Both work on dedicated engine endpoints: an org key on every engine, a project key on its own branch's engines.

Admin Key

Prefix: hb_adm_
Full access: create indexes, push and delete documents, manage settings, and search. Keep this key on your server; never expose it to clients.

Search Key

Prefix: hb_src_
Search through the REST API: search, multi-search, list indexes and get one index, plus write analytics or experiment events. It cannot read tasks, settings or stats, cannot fetch a document by id, and cannot change anything. Safe for client-side and frontend use, but a search returns every field you indexed (below). Search keys are always project-scoped: there is no org-wide search key. A search key reaches every index on its branch, unless it is limited to chosen indexes or chosen engines (below). On a dedicated engine endpoint it can only search.

What a Search Key Can Read

Anyone with your search key can read every field of every document you index. A search with an empty q lists the documents, and each hit carries all of its fields. A search key in a web page is public, so treat everything you index as public.

attributesToRetrieve only trims your own requests. It does not protect anything, because the caller chooses it and can ask for every field. To keep a field private:

  • Leave it out of the documents you send. This works on every engine and is the safe default for emails, names of people, costs and internal notes.
  • On Meilisearch and Visor, set displayedAttributes to the fields results may show. Hits then never carry the others, whatever the request asks for. Typesense and Elasticsearch have no such setting through Headband.
terminal
curl -X PATCH https://headband.dev/v1/indexes/products/settings \
  -H "Authorization: Bearer hb_adm_YOUR_ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{"displayedAttributes": ["id", "title", "category", "price"]}'

Permissions

This table is for the Headband REST API. Dedicated engine endpoints have their own rules, below.

ActionAdmin KeySearch Key
SearchYesYes
List indexesYesYes
Get index infoYesYes
Multi-searchYesYes
View settingsYesNo
View statsYesNo
List or get tasksYesNo
Read raw documentsYesNo
Create indexYesNo
Delete indexYesNo
Add/update documentsYesNo
Delete documentsYesNo
Update settingsYesNo

Rotating a Key

Rotation gives a key a new secret. Its id, name, permissions, branch, lists and expiry stay the same, so only the secret in your app's config changes. The old secret keeps working for a grace period, 24 hours unless you choose otherwise, so you can deploy the new one without downtime. Pick 0 if the old secret leaked.

In the dashboard, open Settings, then Keys, and choose Rotate secret on the key. With the API, call POST /v1/keys/:keyId/rotate with a key that holds keys.manage. The new secret is in apiKey and is shown once.

POST /v1/keys/:keyId/rotate
{
  "gracePeriodSeconds": 3600
}
  • gracePeriodSeconds is 0 to 604800 (7 days). It never runs past the key's own expiry. The answer's previousSecretExpiresAt says when the old secret stops, on Headband and on every dedicated engine endpoint.
  • Tenant tokens signed with the old secret keep working for the same grace period.
  • Rotating again ends the earlier grace period at once. Deleting the key ends both secrets. To end only the grace period early, delete <keyId>.previous.
  • A key can rotate only a key it could have made itself: one on its own branch (any key of the org for an org key) holding no permission it lacks. Any other key answers 404 key_not_found.
  • GET /v1/keys shows a key's previousSecret while it still works, with its last use, so you can tell when no app sends it any more.

Keys for Chosen Indexes

A search key can be limited to chosen indexes, for example one key per app when a branch holds the indexes of several. The key then searches only those indexes. Any other index answers 404 index_not_found, exactly like an index that does not exist. Admin keys cannot be limited this way.

In the dashboard, open Settings, then Keys, click New key, pick a project and the Search type, and list the indexes. With the CLI, pass --indexes. With the API, send indexUids to POST /v1/keys.

terminal
headband keys create storefront --type search --project <project id> --indexes products,categories
POST /v1/keys
{
  "name": "storefront",
  "type": "search",
  "projectId": "<project id>",
  "indexUids": ["products", "categories"]
}
  • The list holds 1 to 100 index uids. An index that does not exist yet is allowed: the key reaches it once it is created on the key's branch.
  • Such a key works on /v1/search, /v1/multi-search, /v1/hybrid-search, /v1/ai/search and /v1/relevance/events. Every other endpoint, the index list and /v1/warm included, answers 403 all_indexes_key_required.
  • It does not work on a dedicated engine's own endpoint, which cannot hold a key to one index: there it answers 401 invalid_credentials.
  • The list is fixed when the key is created. To change it, create a new key and revoke the old one.
  • To give each of your own customers a key to its own data, sign tenant tokens from a search key instead.

Keys for Chosen Engines

An org-scoped admin key, or a branch key, can be limited to chosen dedicated engines, for example one key for staging and one for production in the same organization. An org key then reaches only the indexes on those engines, on every branch. A branch key reaches its branch's engines among them. Both through the REST API and on the engines' own endpoints. (Org keys are admin only, so a limited search key belongs to one branch.)

In the dashboard, open Settings, then Keys, click New key and pick the Chosen dedicated engines scope. With the CLI, pass engine ids from headband instances list. The --instances flag requires CLI 0.4.0.

terminal
headband keys create staging-app --type admin --instances iabcdef012345
terminal, two engines
headband keys create staging-app --type search --project <project id> --instances iabcdef012345,ibcdef012345a

--instances takes one comma-separated list of 1 to 50 ids of your organization's engines. Repeating the flag does not add engines: only the last one counts. With --project (and optionally --branch) the key belongs to that branch, and every engine id must sit on it. Without them the key is an org key.

  • An index on any other engine, or on the shared engines, answers 404 index_not_found, exactly like an index that does not exist. The index list shows only the indexes on the key's engines.
  • On /v1/instances the key sees only its engines. Any other engine answers 404 instance_not_found. Creating an engine needs a key that is not limited.
  • Endpoints that are not about those engines answer 403 org_wide_key_required: key and project management, index creation, schema, Sync, connector runs, experiments, llms.txt and MCP requests.
  • On an engine's own endpoint, an engine that is not on the list answers 401 invalid_credentials.
  • When an engine on the list is deleted, the key loses it. A key whose engines are all deleted reaches nothing: it never becomes org-wide.
  • An owner or admin can change the list later, or remove it, with PATCH /v1/keys/{keyId} and a CLI login key: send {"instanceIds": [...]}, or {"instanceIds": null} for no list. The same rules as at create apply. A narrowed key loses the engines it no longer lists at once.

headband keys list and keys create show an engines column:

  • all is a key that is not limited. It reaches every engine of your organization.
  • Engine ids, such as iabcdef012345,ibcdef012345a, are a limited key. It reaches only those engines.
  • none is a key whose list is empty or unreadable. It reaches no engine.
  • unknown means the API did not report the key's engines. The CLI does not guess: it never shows such a key as all.

Keys on Engine Endpoints

A dedicated engine's own endpoint checks keys differently from the REST API.

  • An org-scoped key works on every engine in your organization. A project-scoped key works only on the engines of its own branch. Any other engine, including another project's, answers 401 invalid_credentials.
  • A key limited to chosen engines works only on those engines. Any other engine answers 401 invalid_credentials.
  • A search key can only search. Settings, stats, documents and the index list answer 403 route_not_allowed.
  • An admin key can search, read, write and manage indexes. Platform routes, such as the engine's own key management, are closed to every key.
  • Send the key in the header your engine's client uses. Authorization: Bearer works on every engine.

See Dedicated Engines for each engine's search routes and header.