IdentArk

Every request authenticates with a bearer key:

Authorization: Bearer csk_…

Real server keys always start with csk_. The dashboard authenticates humans with a Firebase session instead — you never need that as an API client.

Scopes

A scope is a resource:action string. A key carries a list; a route declares what it requires. org:admin is a superscope that implies all others.

Scope Grants
credentials:read / :write List credentials / register, rotate, delete them.
agents:read / :write Read agent inventory & AGBOM / create & edit agents.
sessions:read / :write Read session history & cost / open sessions.
llm:invoke Run LLM calls through the plane.
acs:evaluate Ask the Guardian endpoint for an allow / deny / modify decision.
audit:read Read the immutable action log.
stats:read Read usage analytics.
policies:read / :write Read / manage HITL & approval policy.
org:admin Superscope — everything, including key & org management.

Presets

Pass a single preset name in scopes and it expands at creation time.

read

Every read-only scope. Dashboards, reporting, observers.

invoke

`llm:invoke` + `acs:evaluate` + all reads. The agent / CI key.

admin

Full access, including org administration. Keep it out of agents.
curl -X POST https://api.identark.io/v1/keys \
  -H "Authorization: Bearer csk_ADMIN" \
  -d '{"name":"prod-agent","scopes":["invoke"],"expires_in_days":90}'

When a scope is missing

A request with an under-scoped key returns 403 and names exactly what's missing:

{
  "error_code": "insufficient_scope",
  "message": "This API key lacks the required scope: llm:invoke",
  "required_scope": "llm:invoke"
}

Mint or rotate a key that includes the named scope, and retry.