Generate an API key
Create a new API key with the right scopes for an integration. Walks through a knowledge:read+write key for a doc-as-code pipeline as a worked example.
Before you start
- Admin permissions on API Keys
- A clear answer to “which integration is this for, and what does it need to do?” — that determines the scopes
- A secrets manager ready (1Password, AWS Secrets Manager, Vault, etc.) — the key is shown once at creation and can’t be retrieved again
Steps
- Open Settings → API Keys.
- Click Generate new key.
- Fill in the basics:
Name — descriptive (e.g.KB Sync Script — Production). This is what shows in the keys list and in monitoring dashboards. Don’t be cute; future-you needs to identify which integration each key belongs to.
Description — optional context for maintainers (“Used by the doc-as-code push script in the marketing vault”).
Environment —production(sa_live_*) orsandbox(sa_test_*). - Pick scopes. Two ways:
By bundle — pick frombasic,read_all,integration,full_access, etc. Fast, but can grant more than needed. See scopes reference.
By individual scope — check each scope manually. Slower but lets you grant the minimum. Recommended for production keys. For the doc-as-code use case, pickknowledge:readandknowledge:write. Nothing else. - Pick a rate limit tier —
starter(60/min) is fine for most one-off scripts;professionalfor daily integrations;enterprisefor real-time. See rate limits reference. - Click Generate.
- Copy the key now. It’s displayed exactly once. Atender hashes the key in storage and can’t show it again — losing it means rotating to a new key.
- Store it in a secrets manager. Don’t put it in
.zshrc, don’t paste it in chat, don’t commit it. See Push KB script README for the 1Password pattern we use for the doc-as-code key.
Verify it worked
Test the key against an endpoint matching its scopes. For a knowledge:read+write key:
curl -H "Authorization: Bearer sa_live_..." \
https://prod.atender.dev/api/v1/kb/categories
Expected: a 200 response with the categories list. If you get:
- 401 — the key is wrong (typo, missing prefix, copied with surrounding whitespace)
- 403 — the key is valid but doesn’t have
knowledge:readscope. Re-check the scopes you granted. - 429 — the key is rate-limited. Wait
Retry-Afterseconds and retry.
Naming conventions
For a tenant with multiple keys, naming consistency matters:
<Integration> — <Environment>—KB Sync Script — Production,KB Sync Script — Sandbox<Team> — <Use case>—Marketing — Vault Sync,Engineering — CI Webhooks<Service> — <Purpose>—Datadog — Metrics Pull
Avoid generic names like Production Key, Default, or Test. When something goes wrong (rate limit hit, key compromised), specific names make it instantly clear which integration to investigate.
What gets stored after creation
- Hashed key (for verification) — The actual key text
- Name, description —
- Scopes —
- Rate limit tier —
- Environment —
createdAt,lastUsedAt—
The key text only exists at creation. There’s no admin recovery — losing the key means generating a new one.
Troubleshooting
- Symptom: Generated the key but didn’t copy it; the modal closed. Fix: No way to retrieve. Delete this key (so it can’t be used) and generate a new one with the same scopes.
- Symptom: Curl returns 403 even with the right scope checked.
Fix: The key is
sa_test_*but you’re calling production, or vice-versa. Match the environment. - Symptom: Need to add a scope after the key was generated. Fix: API key scopes aren’t editable after creation. Generate a new key with the wider scope set, update consumers to use it, revoke the old.