Your key
Every request carries Authorization: Bearer <key>. Keys come from the web app once you have signed in — a personal key from Settings, or a project-scoped service account from the Members page when the caller should be your CI or a shared agent rather than you.
Environment variables are client-dependent
The snippets above reference ASKANCE_KEY rather than a literal key, because the key should not end up in a file you commit. How that reference is resolved is up to the client, and they do not agree:
- Claude Code expands
$${ASKANCE_KEY} from your shell environment. - Cursor uses its own
$${env:ASKANCE_KEY} syntax inside url and headers. - Codex takes the NAME of the variable (
bearer_token_env_var) and builds the header itself. - Anything else: check whether your client expands variables at all. Several do not. If yours does not, paste the literal key — and make sure the file it lives in is not committed.
git check-ignore -v <file> tells you before it is too late.
A client that does not expand the variable sends the literal string $${ASKANCE_KEY} as the key, and every call fails authentication with no obvious cause. If your first call returns 401, check this first.
Set the variable so it survives a restart
This is the most common way a working setup quietly stops working. A bare export ASKANCE_KEY=... lasts only for the terminal you typed it in, and an editor launched from a Start menu, Dock or desktop icon never reads your shell profile at all — so the config file looks perfect, the variable resolves to nothing, and every call gets Bearer with no key after it. Set it for your user account instead, then fully restart the app:
- macOS / Linux: append
export ASKANCE_KEY="ask_..." to ~/.zshrc or ~/.bashrc, then open a new terminal. If you launch your editor from an icon rather than that terminal, it may still not see it — launch it from the terminal, or set the variable at the OS level. - Windows:
export is not a command in PowerShell, so this step is silently skipped and nothing is set. Use [Environment]::SetEnvironmentVariable('ASKANCE_KEY', 'ask_...', 'User') instead, which persists for your account.
Then check it actually resolved, from the same account that runs the client: printenv ASKANCE_KEY (macOS/Linux) or $env:ASKANCE_KEY (PowerShell). An empty result is the whole bug — the config is fine and the key was never there.
Personal keys and service accounts
A personal key (Settings) authenticates as you — everything you can do, it can do. A service account (a project's Members page) is a non-human member of one project, and it is what CI and shared agents should use. Two differences matter when you are deciding:
- A service account is scoped to exactly one project, always. It cannot reach a second one, and it cannot create one. If you work across several projects, that is several service accounts — which is the point: a leaked key exposes one project.
- It can hold several keys, one per app. Issue a named key for GitHub Actions and another for your laptop, and revoke the one that leaked without breaking the other. Regenerating a key revokes the old one immediately — there is no grace period, because you regenerate when something has leaked.
- Keys are never re-displayed. They are stored as one-way hashes, so nobody — including us — can recover one after the moment it is created. Lost it? Issue another; that is cheaper and safer than a system that could hand it back.
What a service account is allowed to do
Every service account carries a role, set by a project owner on the Members page. It applies to that account's very next call — no key reissue — so an owner can downgrade something that is misbehaving immediately. If a tool returns a permission error naming a role, this is why.
| Role | Can |
|---|
ReadOnly | Search the record and read: search_records, list_*, get_*, check_*. Writes nothing. |
Askdefault | Everything above, plus ask_question and set_question_escalation. |
Contribute | Everything above, plus propose_direction, report_correction, comment_* and update_project_background. |
Administer | Everything above, plus maintaining the project's topics — create_topic, rename_topic, delete_topic and set_member_topics. |
Grant Administer deliberately. Topic assignments decide who gets notified about a question, so an account that can rewrite them can decide that nobody hears about one — with every call still returning success. It is off by default and an owner sets it explicitly; an existing account never gains it by upgrade.
No role reaches credentials, membership or billing — issuing or revoking keys, changing any account's role (including its own), inviting or removing members, billing, and deleting or transferring the project stay with a human owner whatever an account's role is. Every one of those either mints new credentials or widens the caller's own authority, which would make a leaked key self-perpetuating: being able to downgrade a misbehaving agent is worth nothing if the agent can undo the downgrade.