Loading...

API keys

An API key lets your code do what you do in the console — create, update and delete records, add fields, use the rest of the API — without a person signing in.

Give every program its own key — a read-only one for your website’s search box, a full one for your import script — so you can see which program did what, and delete one without disturbing the others.

1

What an API key is for

An API key lets your code do what you do in the console — create, update and delete records over the API. Keys live under Developers → API Keys, each showing its scope and region. Give each integration its own key so you can see who’s doing what and revoke one without disturbing the others.

The API Keys page
2

Scope it and route its region

Name the key, then choose its scope — the whole account, a single group, or a single list. An account key defaults to your home region; the Region dropdown routes its requests to the right regional API. Optionally set an expiry and pick permissions — leave them empty for full access, or tick just what the integration needs.

The create-API-key dialog
3

A read-only key for a browser embed

For a browser embed, scope the key to one list and hit the Search only preset — read-only, that list and nothing else. A list- or group-scoped key takes its region automatically. Click Create and the secret is shown once — copy it now. Leaked or rotating? Delete it (revocation is immediate) and only that one integration needs a new value.

A search-only key scoped to one list

Auto-plays · use Back / Next to step through at your own pace.

Create a key
  1. Go to Developers → API Keys and click Create API Key.
  2. Give it a name that says what it’s for: ci-deploy, catalogue-sync.
  3. Pick its scope (whole account, one list, one group) and its access, which starts at Search and read. Under Advanced, set an expiry date and pick individual permissions.
  4. Click Create. The secret is shown once — copy it now. It is never shown again.
The Create API Key dialog showing the name, the Scope listbox, the Region dropdown, optional expiry and permissions
Scope: account, list or group

Two separate settings: scope is where a key reaches, permissions are what it can do there.

ScopeReaches
Whole account (default)Every list and group, like your console session. Right for back-office tools and build jobs.
A single listOne list only — never another list, any group, or your account settings.
A single groupOne group and the lists in it.

A key for a web page (autocomplete, public search box) should be list-scoped and read-only: site-search over your products list, Search and read access.

  • It sits in your page’s JavaScript for anyone to read, so scope is the protection: another list name in the URL returns 403.
  • Scope does not hide records inside that list — a read key can page through every one, so only embed over a list you would publish whole.
  • No key can be limited to part of a list. For per-visitor records, query from your own server and filter there.
  • Lock it to your websites so another site can’t embed it: allowed_origins such as ["example.com", "*.example.com"]. A request from any other site (by its Origin, or Referer) gets 403 origin-not-allowed.

Scope also sets the region prefix (ssk_us_…), routing requests to that region’s servers. List- and group-scoped keys take the region from the list or group; a whole-account key defaults to your account’s home region, changeable in the Region dropdown (the regions with an API deployment). Region picks the nearest servers only: an account key works everywhere, so a “wrong” choice costs a slower round trip, not a broken key.

Access: just what it needs

Give a key only the operations its program performs. Access offers three ready-made settings and starts on the narrowest.

AccessCan do
Search and read (default)Search your lists and groups and read their records, paging through every record in scope. The key for a website or app.
Read allView everything (lists, results, facets, models, services); create, edit and delete nothing.
Full accessEvery operation, including deleting data. Fine for a trusted back-office tool, risky for anything the public can reach — treat the secret like a password.

For anything in between, open Advanced and tick individual permissions — grouped by area (account, analytics, API keys, records, fields, evals, media and more), with Access switching to Custom. A key that only adds records needs record-write permissions and nothing else, so a leak cannot delete your lists or read your account.

  • Greyed out: console-only permissions no API key can use (e.g. feed:create, reranker:view).
  • Models (model:*): a key adds or edits an embedding or answer model by naming a saved credential (credential_name); it cannot send a provider key and never sees one.
  • Analytics reports include the text visitors searched for. Read all and Full access keys can read them — a list- or group-scoped one for its list or the group’s lists — and so can a Custom key with analytics:read. Search and read cannot.
  • Two routes reach that text without analytics:read: user generated suggestions (generated-suggestions:create or :edit) copy past searches into a list, and query-rule inference from searches (query-rule:create) returns example searches.

Keys work on the public API. A 403 where you expected success is almost always a missing permission — widen access and create a new key, or test with a Full access key.

Create a read-only key from the API

Key management stays in the console, with one exception: a key (or an agent using the MCP tools) holding api-key:create-read-only can create a read-only key of any scope — the building block for handing each page, or each customer of yours, its own narrow key.

POST to /api-key/read-only with the new key’s name, the account, the read permissions you want (anything ending :read or :view; writes are dropped, at least one read is required), and an optional scope/scope_target. The response carries the usable key once:

curl -X POST https://api.searchstack.dev/api-key/read-only \
  -H "X-API-Key: $ACCOUNT_KEY" -H "Content-Type: application/json" \
  -d '{ "account_name": "acme", "api_key_name": "site-search",
        "permissions": ["search-result:read", "list:read"],
        "scope": "list", "scope_target": "products" }'
  • The new key holds read permissions only, so it can never write and never create another key.
  • Its scope can only match the creating key’s, or be narrower.
  • It expires no later than the creating key: a later (or missing) expires_utc is capped at the creating key’s expiry.
  • The endpoint is rate-limited.
  • Both client libraries offer it (client.ApiKeys.CreateReadOnly…). Shapes are in the API reference.
  • Delete a read-only key with DELETE /api-key/read-only/{account}/{key} (client.ApiKeys.DeleteReadOnly…). Needs api-key:delete-read-only, which no key has by default — only a key created naming it. Refused for a key that can write, a full-access key, and the calling key.
  • Lock a read-only key to websites with PUT /api-key/read-only/{account}/{key}/allowed-origins and { "allowed_origins": ["example.com"] } (client.ApiKeys.SetAllowedOrigins…); an empty list unlocks it. Needs api-key:create-read-only. Takes effect within the hour.
  • Websites: a host (example.com), any subdomain (*.example.com, not the apex) or a port (localhost:3000); the scheme is ignored, at most 20. A wildcard on a shared host (*.github.io, *.vercel.app, …) is refused; name your own subdomain instead. A key locked to websites can only create keys locked to the same websites or fewer. It stops another site embedding the key; it does not stop a script that fakes the header.

For an agent, include list:read: it lets the agent call GET /list/{account} and discover your list names, without which it reaches only lists you named exactly. GET /account returns the account name for any valid key; list-group:read does the same for groups.

Expiry, rotation and revocation
  • Expiry — the key stops working after the date you set, on its own. Good for temporary access: a data move, a contractor.
  • Rotation (swapping a key for a fresh one) — create a new key, switch your program over, delete the old one. Both work while you swap.
  • Last used — the date each key last signed in (last_used_utc), on the Developers page. When the old key’s date stops moving, it is safe to delete.
  • Revocation (cancelling a key) — deleting a key stops it working immediately. The fix for a leaked secret; with a key per program, only that one needs a new value.
Top