Authentication
Bearer Header
Include your API key as a Bearer token in the Authorization header on every request:
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
displayedAttributesto 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.
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.
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.
{
"gracePeriodSeconds": 3600
}gracePeriodSecondsis 0 to 604800 (7 days). It never runs past the key's own expiry. The answer'spreviousSecretExpiresAtsays 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/keysshows a key'spreviousSecretwhile 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.
headband keys create storefront --type search --project <project id> --indexes products,categories{
"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/searchand/v1/relevance/events. Every other endpoint, the index list and/v1/warmincluded, answers403 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.
headband keys create staging-app --type admin --instances iabcdef012345headband 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/instancesthe key sees only its engines. Any other engine answers404 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:
allis 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. noneis a key whose list is empty or unreadable. It reaches no engine.unknownmeans the API did not report the key's engines. The CLI does not guess: it never shows such a key asall.
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: Bearerworks on every engine.
See Dedicated Engines for each engine's search routes and header.