Skip to content
Console
Browse documentation
Reference

Authentication and API keys

Create, scope, send, rotate, and revoke Anectico credentials safely.

On this page

Human Console sessions and programmatic API keys are separate credentials. Use API keys for SDKs, collectors, CI, CLI automation, and MCP clients. Public capture and OTLP use separate purpose-bound native intake keys; management credentials cannot enter those routes.

OAuth for connected agents

An OAuth-capable MCP host can connect through sign-in and workspace consent. It uses S256 PKCE and the MCP URL as its resource. Registration supports public clients, including clients that omit token_endpoint_auth_method; the response selects none. Client metadata documents must be reachable at a public HTTPS URL, identify that same URL, fit within 5 KiB, and avoid redirects.

OAuth permits reads only. Requests for write scopes return invalid_scope. Writes require an owner-created API key with the required permissions. See Connect MCP.

Refresh tokens rotate. An identical retry within five seconds receives the same rotation; a simultaneous request may return 503 temporarily_unavailable with Retry-After: 1. Retry after that delay. Reusing a consumed refresh token after five seconds revokes its approval and requires fresh consent. Other approvals stay connected.

To stop an approval, use Agents and keys or your human CLI login. There is no advertised OAuth token revocation endpoint. See Revoke agent access.

Create a key

An agent connected through OAuth cannot create a key, because OAuth permits reads only. An agent with an owner-created management API key that holds mcp:write, api_key:write and every scope the new key carries can create one when you ask, with the CLI (anectico apikey create) or the MCP write actions create_intake_key for intake and create_api_key for management, server application or client-delivery credentials. Each is created only after you approve its complete preview, and a telemetry or capture key is bound to one exact project. The secret goes into the application's environment or secret store, never into source code, a log or a transcript you share. To create a key yourself, open Agents and keys in the Console (/agents), then API Keys. Select Telemetry (OTLP), Browser capture, Mobile capture, Server capture, or Management / agent, then choose a project. Intake purposes have one fixed permission: ingest:write for telemetry, analytics:write for capture. Only management keys offer read or full presets and custom permissions; management keys cannot send public capture or OTLP.

An optional existing source ID must match the selected project and intake purpose. Leave it empty to use that project's default source for the purpose. The list shows each key's purpose and source. Editing cannot change purpose, project or source; Allow intake can disable or restore a native key's single permitted scope.

Choose how long the key should remain valid. Never is the default; fixed choices from one day through one year create a key whose expiry is shown with its metadata. Expiry cannot be extended after creation. The secret is shown once and is never stored in browser storage.

After a connection failure, Retry same request keeps the original arguments and expiry. An already committed request returns metadata only; revoke that key in the list before creating a replacement if you lost its secret. Closing the form or leaving the page discards the in-memory retry state, so check the key list before starting again. Project, session and permission changes also clear displayed secrets and pending form state.

You can also create keys through the account API, CLI or MCP; see native intake keys. Creating a key in the Console supplies a retry key automatically. API and CLI retry keys are optional; MCP creation requires one.

The account API accepts the same optional expiry as an RFC3339 timestamp. Generate the expiry immediately before submitting the request rather than copying a fixed calendar date. With Node.js installed, this prints a one-day JSON payload; it does not create a key or send a request:

node <<'JS'
const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString();
console.log(JSON.stringify({
  name: 'One-day CI key',
  scopes: ['traces:read'],
  expires_at: expiresAt,
}, null, 2));
JS

Send the resulting JSON to POST https://app.anectico.com/api/v1/account/api-keys using an existing credential with api_key:write; it can grant only scopes the caller is allowed to grant. Choose the intended project_id as described below; omitting it does not create an organization-wide key. Do not commit or log the returned plaintext key.

Omit expires_at for a key that never expires. A supplied timestamp must be in the future and no more than 365 days from creation. An expired key is rejected on its next use; revocation remains immediate and permanent.

Owner work limits live in a separate policy. Edit Agent budget beside the management key or use anectico budget set --file budget.json. Queries, writes, destructive writes and exports have hourly and daily limits, plus concurrency. See Manage agent budgets.

Anectico keys begin with an_. Treat the rest as opaque; do not parse meaning from it.

Send an API key

The public REST API accepts:

X-Anectico-API-Key: an_...

It also accepts the generic X-API-Key header and Authorization: ApiKey an_.... MCP clients normally use:

Authorization: Bearer an_...

Use the header documented by the SDK or client you are configuring rather than sending multiple credential headers.

Common key recipes

Scopes use resource:action names.

Purpose Required starting scopes
OTLP traces, logs, metrics, and captured errors purpose: native_ingest, only ingest:write
Product capture, identity and group controls purpose: browser_capture, mobile_capture or server_capture, only analytics:write
Browser session replay replay:write
Evaluate feature flags on your server and record exposures Management flags:read key held on the server; separate capture key for exposures
Evaluate named feature flags from your page or app purpose: client_delivery, only flags:evaluate; exposures use a separate capture key
Assign people to product experiments and record exposures and outcomes (your application server) purpose: application, only experiments:deliver
Show in-product surveys from your page or app and record answers purpose: client_delivery, only surveys:respond
Upload native replay chunks from your app purpose: replay_upload, only replay:write
Upload source maps, ProGuard mappings, or dSYM binaries errors:write
Register a release in CI releases:write
Read through MCP mcp:read plus the required domain read scopes
Read documentation through MCP mcp:read and docs:read
Allow MCP writes mcp:read, mcp:write, and the required domain-specific scopes
Read service health from an app you host, such as a status board A dedicated management key for that app, bound to one project, only services:read, with a fixed expiry. See the key for an app you host
Search logs logs:read
Read traces traces:read
Read or triage Issues errors:read or the required error write scope
List the organization's API keys api_key:read
Create, rename, revoke, or re-scope API keys api_key:write

mcp:read is an umbrella, not permission to read every domain. For example, an MCP trace reader also needs traces:read; a docs-only agent needs docs:read instead. A write scope does not imply its matching read scope. URL profiles may further hide capabilities, but cannot grant missing scopes. Start with agent scope recipes and check the agent security model before granting writes.

Use distinct credentials for capture, OTLP and management APIs. A native key cannot gain replay, flag-read or management scopes, and cannot exchange for a management bearer token. Choose the explicit intake purpose when generating a key; scope names alone do not grant intake authority. See the supported SDK setup paths in native intake keys.

An application key (purpose: application) is a secret for your application server. It is bound to one project, carries only experiments:deliver and cannot be widened; no member role and no ordinary key can hold that scope. Only an owner or admin (who holds experiments:launch) can create one. It assigns identified people to product experiments, registers the first exposure and records outcome receipts for its own project — nothing else. It is secret authority, not proof that a request came from server hardware: never ship it in browser or mobile code, and revoke it if it leaks. Record the outcome event itself with a separate server_capture key. The word "application" here means server-side experiment delivery. It is not the key for an app that reads your data: it reads nothing, and an app that reads uses the management key described next.

A client delivery key (purpose: client_delivery) is the public key you place in your own page or app build, where anyone who installs or opens it can read it. It is bound to one project, carries no intake purpose and holds only flags:evaluate, surveys:respond or both, chosen explicitly when you create it. It can list no flag or survey, read no targeting, stored property or event, change nothing and mint nothing; its purpose and project never change, and a scope edit can only stay within those two scopes. Requests made with it are your software's traffic, never agent activity. You create it with the existing key creation flow, and you need api_key:write plus each scope you grant (members hold both). Issue one key for surveys and a separate one for flags unless one build needs both:

anectico --project PROJECT_ID apikey create --purpose client_delivery --scope surveys:respond \
  --name "web app surveys" --expires-in 90d

Client delivery keys authenticate only POST /api/v1/flags/evaluate, POST /api/v1/surveys/eligible, and the shown, responses and dismissals POST routes beneath /api/v1/surveys/{surveyId}. Flag exposure events use a separate capture key. Experiment delivery and its exposure and outcome receipts use the separate server application key described above.

A replay upload key (purpose: replay_upload) is bound to one project and carries only replay:write. It authenticates only POST /api/v1/replay/chunks; upload still requires current native replay settings and independent storage permission. It cannot read or delete a replay.

Both software purposes are refused on every other authenticated endpoint, including MCP, streaming logs, account and session controls, the scope catalog and authenticated documentation. The response is HTTP 403 with error: permission_denied and a fixed purpose message. Exchanging a key for a signed token does not widen its reach. Public discovery and independently authorized public protocols grant no authority from either key. Browser app-view reads use their own credential scheme. They reject ordinary Authorization credentials with 401 access_ended; credential-bearing app-view preflights are refused with 403. API-key headers on either method are refused with 400 invalid_request.

Use a separate stable --idempotency-key for each proposal. The command prints the full proposal (purpose, project, scopes and fixed expiry) and a confirmation token; repeat it with --confirm-token, --idempotency-key and the printed --expires-at to create the key. The secret is shown once; a retry returns the metadata without it. A key created with surveys:respond works on the survey delivery routes. A key created with flags:evaluate works on POST /api/v1/flags/evaluate, which returns decisions for the 1 to 100 flag keys the app names and never a definition:

anectico --project PROJECT_ID apikey create --purpose client_delivery --scope flags:evaluate \
  --name "mobile app flags" --expires-in 90d

Client-side feature flags use that key and nothing broader. Never put a flags:read key in a page or app: it also reads every flag definition, targeting rule and payload of the project. Exposures still go through a separate capture key. An agent uses its own management credential to configure and verify; public client evaluation uses the separate delivery key. The existing server integration workflow does not wire flags into client code and does not qualify mobile delivery. Native source APIs and their pending runtime qualification are in mobile setup. See Feature flags from a page or app.

The Access screen is the current source for the complete scope catalog. See the permission scope reference for the selectable groups and safe key patterns.

Which credential each host holds

A program your agent writes against the API holds one credential, and where the program runs decides which one. You host the program and keep its secret; Anectico supplies the API and the credentials. Build an app on the REST API says what such a program is.

Host Credential it holds
Your backend or an internal tool A dedicated management key for that app, bound to one project, in the host's secret store.
A browser page, or a page in a chat host None of Anectico's. It calls your own fixed, authenticated backend API. No management key appears in the page's assets, storage, network traffic or address.
A mobile app No management key. Reads of protected data go through your backend. Its SDK uses separate public native-ingest and mobile-capture credentials, plus explicitly configured client-delivery keys for flags and surveys.
A Slack bot A secret on the bot's server. That server authenticates and authorizes each workspace and each user's command itself.
A scheduler (cron) A dedicated least-permission key in the scheduler's secret store, with a fixed project and explicit query windows.
Public telemetry The existing capture, replay or survey key, for the matching SDK operation only.
A browser reading an approved saved aggregate directly A temporary app_read token minted by its exact backend parent; at most five minutes, one approved result and projection, exact origins, no refresh. Recipe.

A read-only management key is never public. It cannot write, but a project-wide read discloses your customers' data, and CORS does not protect it: CORS decides whether a browser may read a response, not whether the request runs. Do not put one in a page, a mobile binary, a repository or a log. The key is not limited to named routes, resources or origins, so your backend enforces which of its own users may see which route, resource, project and field.

Three other credentials look like candidates and are not:

  • The application purpose is server-side experiment delivery under experiments:deliver. It reads nothing, so it is not a key for an app that reads your data.
  • A capture, replay, survey or telemetry key is for sending data from its SDK. It cannot read. A client delivery key is the survey and flag evaluation key placed in an app; it cannot read your data either.
  • OAuth is how your agent discovers and investigates through MCP while it builds the app. It is not a way to give an app, or a browser, access.

The key for an app you host

Give each deployed app its own key, so that you can see exactly what it holds and stop it alone.

  • Name. Name it for the app, such as status-board.
  • Project. Bind it to the one project the app reads. The binding is fixed for the life of the key.
  • Permissions. Grant only what the app calls. A service-health board needs services:read and nothing else: not mcp:read (MCP is how your agent works with Anectico, not how the app reads), not api_key:write, and nothing for billing, members, connections or privacy. Do not use a bundle such as investigate. Add a permission that releases customer content (persons:profile:read, replay:content:read or agents:content:read) only when the app must show that content.
  • Expiry. Choose a fixed expiry in the future and replace the key before it arrives.
  • Limits. The key has its own operation budget and request rate, set under Agent budget beside it on Agents and keys. They slow or block the key. They do not end it.

The worked examples list the exact permissions each kind of app needs, and Give an app its own key is the checklist. Your agent provisions the key and you confirm it:

anectico --project PROJECT_UUID apikey create --name status-board --scope services:read \
  --expires-in 90d --idempotency-key status-board-1
# Review the complete server preview, then repeat the arguments with the fixed expiry it printed:
anectico --project PROJECT_UUID apikey create --name status-board --scope services:read \
  --expires-at <expiry> --idempotency-key status-board-1 --confirm-token <server-token>

The secret appears once, in the first successful response. It is not in the audit log, the activity record, a retry or any later read. If that response is lost, repeat the same command with the same --idempotency-key. You get the original key's details and no secret, and no second key is created. If you never saw the secret, revoke that key and create a new one with a new --idempotency-key.

The credential that provisions the key is the builder's own, not the app's. It holds api_key:read and api_key:write, plus mcp:write for the preview and confirmation, plus every permission it grants. An app's runtime key never creates, lists, edits or revokes keys: those are customer controls, and every route that does them refuses it.

What the key means. The key identifies your application, not your application's users. Anectico records each call under the key's name, and your backend decides which of its own users may see what and records who asked. Do not send your users' session tokens or ids to Anectico as if it had verified them.

A page that shows a saved result to its visitors

A management key never goes into a browser. For a page that must read Anectico directly, an owner creates an app-view grant instead: a permission, separate from every read, for one project's key to mint short-lived browser tokens that show exactly the saved trend results the grant names, through a fixed set of aggregate fields, to exact https:// page origins, until a fixed expiry of at most 90 days.

  • What a grant can show. Counts, values, coverage and window facts of a saved trend result without a breakdown. Never the people, rows, labels, definition, filters or participant lists behind it; never a query run, a write or anything else.
  • Who can create one. An owner or admin, or a management key an owner gave app_views:share together with api_key:read and api_key:write. The key a grant names as its data source holds app_views:mint, analytics:read, persons:read and the results' own permissions.
  • What stops it. Revoking the grant, revoking or expiring that key, removing a permission from it, the grant's own expiry, or turning sharing off in the project's content policy. A grant cannot be widened: a change is a new grant and a revocation of the old one.
  • What it cannot undo. Numbers a visitor already saw or copied.

Use app-view grant list/create/revoke or the MCP gateway actions list_app_view_grants, create_app_view_grant and revoke_app_view_grant. Creation and revocation require the server's complete reviewed confirmation and state fence. Owners review every grant on Agents and keys; sharing consent is on Privacy. Token mint is a separate backend and CLI protocol with a required private --out, never a normal MCP token-read action. Read the complete browser aggregate recipe, including theft and external-copy limits.

Stop an app

Revoke the app's key. It is the one action that stops the app's next request, a read included. Open Agents and keys, or run anectico apikey revoke. Two other actions look like stops and are not:

  • Freeze removes a key's write permissions and keeps its read permissions. A key that only reads keeps reading. An agent-level kill reaches only keys that declared which agent they belong to, and an app's key normally declares none.
  • A limit of zero, on operations or on the request rate, makes the key's requests answer 429. The key is still valid and you can lift the limit. It is a throttle.

Revoking does not stop the program that holds the key, retract data it already read, or undo an effect it already caused. Its caches, exports, logs and messages are yours to delete; Anectico's erasure cannot reach them. See Revoke an agent's access.

Project scope

A project-scoped key may omit a query-string project_id or repeat its exact signed project. A different non-empty value returns 403 permission_denied before product logic runs; Anectico never silently substitutes the signed project for an explicitly conflicting selection. Organization-level keys retain request-time project selection, and many REST reads accept project_id as a query parameter.

A key created without a project selection is bound to the organization's default project. Creating an organization-level key is an explicit choice: send "org_wide": true in the create-key request (the CLI's anectico agent bootstrap --org-wide does this), and the key is minted with no project binding at all. This is available only for management keys; native intake keys always require a project.

The project binding is fixed for the life of a key. To move a workload to another project, create a replacement key for that project, deploy it, verify traffic, and revoke the old key.

That binding is also an authority floor when one API key creates another. A project-scoped key with api_key:write can create a successor only in its own project; requesting org_wide or naming a sibling project returns 403 forbidden. Omitting the project keeps the creator's project — it never widens the successor because the default project cannot be resolved.

Scope edits, expiry, and revocation take effect on the next request because the API key's authorization is resolved server-side for every request, whether it arrives as telemetry or as an API call; successful checks are not cached. If that authorization check is unavailable, API-key OTLP and Capture requests fail closed with a retryable service-unavailable response. Removing traces:read, logs:read, metrics:read, errors:read, search:read, persons:read, or groups:read immediately makes the corresponding Query API return 403; a native OTLP key continues to ingest only while its source is active and ingest:write remains present.

Every native key is bound to an intake source (see ingestion sources and pipelines), and revoking that source stops every key bound to it immediately, independent of the key's own expiry or scopes. The refusal is explicit and named the same way everywhere: an an_ capture key refused for this reason gets 403 forbidden with an X-Anectico-Refusal-Reason: INGRESS_SOURCE_REVOKED response header; OTLP over HTTP returns 403 with the message intake source revoked; OTLP over gRPC returns PermissionDenied with the same message. A project's default source (the one used implicitly when a key omits source_id) is never recreated once revoked — the project keeps that purpose's default permanently unavailable until a new source is created explicitly and new keys are minted against it with source_id.

Rotate and revoke

Create the replacement key, deploy it, confirm traffic uses it, then revoke the old key. Revoke immediately if a key is committed, logged, included in a screenshot, or exposed to an untrusted client.

CLI key creation, updates and revocation first print the complete server preview. Apply only by repeating identical arguments with its --confirm-token and the same --idempotency-key. Copy any generated name and fixed expiry from the preview. Key secrets are returned once and never included in activity records or retries.

Publishable static-page authority

A static aggregate page deliberately publishes one finite app_publishable credential, delivered once by confirmed grant creation with publishable_result_id. It uses only Authorization: AppPublishable on the exact published aggregate route and expires within 30 days. Anyone copying it can read that projection with a forged Origin. It authenticates no ordinary REST, MCP, CLI, cookie, Live or credential-exchange operation. Keep its parent management key secret; revoke the grant or parent to stop future reads.

Native replay upload authority

Use a separate project-bound replay_upload purpose carrying exactly replay:write for native structural uploads. It has no intake purpose and cannot read recordings, upload browser DOM, change configuration, use MCP or exchange into a management bearer. Its software uploads are excluded from agent activity and agent budgets by their signed purpose. The application also needs its separate mobile configuration credential.

An authorized agent provisions it through existing API-key management and must hold literal replay:write for the same active project plus api_key:write (and mcp:write for the confirmed MCP flow). Preview the exact purpose, project and scope, confirm once and preserve the creation retry key after uncertainty. An organization-wide key, wildcard or extra scope is refused. This publishable software key is not device attestation or proof of a person's consent. Native recorder and reader support still requires qualification.