ZeroID REST APIs
Interactive reference for the ZeroID REST API. ZeroID is Highflame's open-source agent identity layer — it issues OAuth2 tokens for non-human identities (agents, applications, MCP servers, services), manages their lifecycle, and enforces credential policies.
All SDKs (Python, TypeScript, Rust) are thin clients over these endpoints.
Base URL
Production (managed)
https://api.zeroid.io
Self-hosted
Your deployment URL
Local dev
http://localhost:8899
Authentication
ZeroID has two distinct API surfaces with different authentication models.
Public token endpoints (/oauth2/*, /.well-known/*, /health, /ready) require no Authorization header. Tenant context and identity are derived entirely from the credential material in the request body (API key, client credentials, JWT assertion, etc.).
Admin endpoints (/api/v1/*) manage identity registration and lifecycle. By default they have no built-in authentication — protect them at the network layer (reverse proxy, VPN, firewall). When the AdminAuth hook is configured, requests must carry:
Authorization
Bearer zid_sk_... (API key) or Bearer <jwt>
X-Account-ID
Account identifier (multi-tenant)
X-Project-ID
Project identifier (multi-tenant)
The X-Account-ID and X-Project-ID headers are required on every admin request — they scope all read and write operations to the correct tenant.
Public Endpoints
POST /oauth2/token
Issue an access token. The grant type determines which credential fields are required. No Authorization header or tenant headers — tenant context is resolved from the credential material.
Common fields:
grant_type
string
Yes
One of: api_key, client_credentials, urn:ietf:params:oauth:grant-type:jwt-bearer, urn:ietf:params:oauth:grant-type:token-exchange, authorization_code, refresh_token
scope
string
No
Space-delimited requested scopes
account_id
string
Depends
Required for client_credentials and authorization_code grants
project_id
string
Depends
Required for client_credentials and authorization_code grants
api_key grant — exchange a zid_sk_* API key for a short-lived JWT:
api_key
Yes
The zid_sk_* API key
client_credentials grant — M2M token for a registered OAuth client:
client_id
Yes
OAuth client identifier
client_secret
Yes
Client secret (confidential clients only)
account_id
Yes
Tenant account ID
project_id
Yes
Tenant project ID
urn:ietf:params:oauth:grant-type:jwt-bearer grant — present a self-signed JWT assertion (RFC 7523). The identity must have a registered public_key_pem:
subject
Yes
Signed JWT assertion (ES256 or RS256)
scope
No
Requested scopes
urn:ietf:params:oauth:grant-type:token-exchange grant — delegate or impersonate (RFC 8693):
subject_token
Yes
The token being exchanged
subject_token_type
Yes
URI identifying token type, e.g. urn:ietf:params:oauth:token-type:access_token
actor_token
No
Actor token for NHI delegation chains
authorization_code grant — redeem an authorization code (PKCE supported):
code
Yes
Authorization code JWT
client_id
Yes
OAuth client identifier
redirect_uri
Yes
Must match the URI used during authorization
code_verifier
No
PKCE S256 verifier
account_id
Yes
Tenant account ID
project_id
Yes
Tenant project ID
refresh_token grant — obtain a new access token using a refresh token:
refresh_token
Yes
Refresh token (zid_rt_*)
Example response (all grant types):
Error response (RFC 6749 §5.2):
POST /oauth2/token/introspect
Introspect a JWT per RFC 7662. Returns active: false for expired, revoked, or unrecognised tokens — never an error.
token
Yes
JWT to introspect
Example response (active token):
Example response (inactive token):
POST /oauth2/token/revoke
Revoke a token per RFC 7009. Always returns 200 — whether the token exists or not.
token
Yes
JWT to revoke
Example response:
GET /oauth2/token/verify
Forward-auth endpoint for reverse proxies (nginx auth_request, Caddy forward_auth, Traefik forwardAuth). Reads the Bearer JWT from Authorization, introspects it, and returns 200 with identity claims as response headers on success, or 401 on failure.
On success, the following headers are set on the response (the proxy copies them into the upstream request):
X-Forwarded-User
sub
WIMSE URI of the identity
X-Zeroid-Identity-Type
identity_type
agent, application, etc.
X-Zeroid-Trust-Level
trust_level
first_party, verified_third_party, unverified
X-Zeroid-Account-ID
account_id
Tenant account ID
X-Zeroid-Project-ID
project_id
Tenant project ID
X-Zeroid-External-ID
external_id
Identity external ID
X-Zeroid-Act-Sub
act.sub
Delegating actor subject (token exchange only)
Example response (200 OK):
GET /.well-known/jwks.json
Returns the server's public key set (JWK Set). Use this to verify JWTs issued by ZeroID without calling back to the server. Keys are ECDSA P-256 (ES256) and optionally RSA 2048 (RS256).
Example response:
GET /.well-known/oauth-authorization-server
OAuth 2.0 Authorization Server Metadata (RFC 8414). Describes supported grant types, endpoints, and signing algorithms.
Example response:
GET /health
Liveness check. Always returns 200 while the process is running.
Example response:
GET /ready
Readiness check. Verifies database connectivity. Returns 503 if the database is unreachable.
Example response:
Admin Endpoints
All admin endpoints require X-Account-ID and X-Project-ID headers. When AdminAuth is configured, also include Authorization: Bearer zid_sk_... or Authorization: Bearer <jwt>.
Agents
The Agent API is a high-level convenience layer. A single registration call atomically creates an identity and issues an API key. Use this for the common case of registering an agent that authenticates with a zid_sk_* key.
POST /api/v1/agents/register
Register a new agent. Creates an identity and an API key in a single atomic operation. Returns the plaintext API key — it is shown only once.
name
string
Yes
Human-readable name
external_id
string
Yes
Unique identifier within this project
identity_type
string
No
agent (default), application, mcp_server, service
sub_type
string
No
Role within the identity type (see table below)
trust_level
string
No
unverified (default), verified_third_party, first_party
framework
string
No
Agent framework, e.g. langchain, autogen, crewai
version
string
No
Agent version string
publisher
string
No
Publisher or organization
description
string
No
Human-readable description
capabilities
JSON array
No
List of capability strings
labels
JSON object
No
Key-value labels for filtering
metadata
JSON object
No
Opaque product-specific metadata
created_by
string
No
User ID of the creator
public_key_pem
string
No
PEM-encoded EC P-256 public key for jwt_bearer and token_exchange grants
Valid sub_type values by identity_type:
agent
orchestrator, autonomous, tool_agent, human_proxy, evaluator
application
chatbot, assistant, api_service, code_agent, custom
mcp_server
(none)
service
llm_provider
Example response:
The plaintext_key is shown once. Store it securely — it cannot be retrieved again.
GET /api/v1/agents/registry
List agents for the current tenant. Supports filtering and pagination.
identity_type
Filter by type: agent, application, mcp_server, service (comma-separated for multiple)
label
Filter by label in key:value format, e.g. team:research
trust_level
Filter by trust level
is_active
Filter by active status (true / false)
search
Search by name or external_id
limit
Items per page (default 20, max 100)
offset
Pagination offset (default 0)
Example response:
GET /api/v1/agents/registry/{id}
Get a single agent by its identity UUID.
Returns the same shape as a single item in the list response above.
PATCH /api/v1/agents/registry/{id}
Update mutable fields of an agent. All fields are optional — only provided fields are updated.
name
string
Human-readable name
sub_type
string
Operational role
trust_level
string
Trust level
framework
string
Agent framework
version
string
Agent version
publisher
string
Publisher
description
string
Description
capabilities
JSON array
Capabilities
labels
JSON object
Key-value labels
metadata
JSON object
Opaque metadata
status
string
active, suspended, or deactivated
Returns the updated agent object.
DELETE /api/v1/agents/registry/{id}
Soft-delete an agent — deactivates the identity and revokes all its API keys. The identity record is retained for audit purposes.
Returns the final agent state with status: "deactivated".
POST /api/v1/agents/registry/{id}/activate
Activate a previously deactivated or pending agent.
Returns the updated agent with status: "active".
POST /api/v1/agents/registry/{id}/deactivate
Deactivate an agent without deleting it. The agent can be reactivated later.
Returns the updated agent with status: "deactivated".
POST /api/v1/agents/registry/{id}/rotate-key
Rotate an agent's API key. Revokes the existing key and issues a new one. Returns the plaintext key — shown once only.
Example response:
Identities
Lower-level identity management. Use the Agents API for the common registration case. Use Identities directly when you need fine-grained control or want to attach credentials separately.
POST /api/v1/identities
Create a new identity without automatically issuing credentials.
external_id
string
Yes
Unique identifier within this project
owner_user_id
string
Yes
User ID of the identity owner
name
string
No
Human-readable name
identity_type
string
No
agent, application, mcp_server, service
sub_type
string
No
Role within identity type
trust_level
string
No
unverified, verified_third_party, first_party
allowed_scopes
string array
No
OAuth scopes this identity may request
public_key_pem
string
No
PEM-encoded ECDSA P-256 public key for jwt_bearer grant
framework
string
No
Agent framework
version
string
No
Version string
publisher
string
No
Publisher or organization
description
string
No
Human-readable description
capabilities
JSON array
No
Capability list
labels
JSON object
No
Key-value labels
Example response:
GET /api/v1/identities
List identities for the current tenant.
identity_type
Filter by type (comma-separated for multiple)
label
Filter by label in key:value format
trust_level
Filter by trust level
is_active
Filter by active status (true / false)
search
Search by name or external_id
limit
Items per page (default 20, max 100)
offset
Pagination offset
Example response:
GET /api/v1/identities/{id}
Get a single identity by UUID.
Returns the full identity object.
PATCH /api/v1/identities/{id}
Update mutable fields of an identity. All fields are optional.
name
string
Human-readable name
identity_type
string
Identity type
sub_type
string
Sub-type
trust_level
string
Trust level
owner_user_id
string
Owner user ID
allowed_scopes
string array
Permitted scopes
public_key_pem
string
ECDSA public key PEM
framework
string
Framework
version
string
Version
publisher
string
Publisher
description
string
Description
capabilities
JSON array
Capabilities
labels
JSON object
Labels
status
string
active, suspended, or deactivated
Returns the updated identity object.
DELETE /api/v1/identities/{id}
Soft-delete (deactivate) an identity. Returns 204 No Content.
Credential Policies
Credential policies define governance constraints enforced at token issuance time — max TTL, allowed grant types, required trust level, and delegation depth. Policies are templates assigned to API keys.
POST /api/v1/credential-policies
Create a new credential policy.
name
string
Yes
Policy name (unique per tenant)
description
string
No
Human-readable description
max_ttl_seconds
integer
No
Maximum token TTL in seconds (default 3600)
allowed_grant_types
string array
No
Permitted grant types (e.g. ["api_key", "client_credentials"])
allowed_scopes
string array
No
Permitted OAuth scopes
required_trust_level
string
No
Minimum identity trust level required
required_attestation
string
No
Minimum attestation level required
max_delegation_depth
integer
No
Maximum delegation chain depth (default 1)
Example response:
GET /api/v1/credential-policies
List all credential policies for the current tenant.
Example response:
GET /api/v1/credential-policies/{id}
Get a single credential policy by UUID.
Returns the full policy object.
PATCH /api/v1/credential-policies/{id}
Update a credential policy. All fields are optional.
name
string
Policy name
description
string
Description
max_ttl_seconds
integer
Max token TTL
allowed_grant_types
string array
Permitted grant types
allowed_scopes
string array
Permitted scopes
required_trust_level
string
Required trust level
required_attestation
string
Required attestation level
max_delegation_depth
integer
Max delegation depth
is_active
boolean
Enable or disable the policy
Returns the updated policy object.
DELETE /api/v1/credential-policies/{id}
Delete a credential policy. Returns 204 No Content.
API Keys
Standalone API key management. API keys are prefixed zid_sk_*, hashed with SHA-256, and shown in plaintext only at creation. Use the Agent API (/api/v1/agents/register) to create a key bound to a new identity atomically; use this API to create additional keys for existing identities or manage keys directly.
POST /api/v1/api-keys
Create a new API key.
name
string
Yes
Human-readable key name
description
string
No
Key description
identity_id
string
No
UUID of the identity to link this key to
product
string
No
Product namespace for key scoping
scopes
string array
No
Allowed OAuth scopes
environment
string
No
live (default) or test
expires_in_days
integer
No
Key expiry in days (omit for no expiry)
metadata
JSON object
No
Arbitrary JSON metadata
Example response:
GET /api/v1/api-keys
List API keys for the current tenant.
product
Filter by product namespace
application_id
Filter by linked identity ID
label
Filter by identity label in key:value format
page
Page number (default 1)
limit
Items per page (default 20, max 100)
Example response:
GET /api/v1/api-keys/{id}
Get a single API key by UUID. The raw key value is never returned — only metadata.
Returns the full key metadata object.
POST /api/v1/api-keys/{id}/revoke
Revoke an API key immediately. Any tokens issued with this key remain valid until their exp claim. To also invalidate issued tokens, revoke them via POST /oauth2/token/revoke.
reason
string
No
Human-readable revocation reason
Example response:
CAE Signals
Continuous Access Evaluation (CAE) signals notify ZeroID of security-relevant events affecting an identity. Signals trigger downstream token evaluation and can cause active sessions to be terminated.
Valid signal_type values: credential_change, session_revoked, ip_change, anomalous_behavior, policy_violation, retirement, owner_change.
POST /api/v1/signals/ingest
Ingest a CAE signal for an identity.
signal_type
string
Yes
Type of the signal (see valid values above)
source
string
Yes
System or service that generated the signal
identity_id
string
No
UUID of the affected identity
severity
string
No
low (default), medium, high, critical
payload
JSON object
No
Arbitrary signal payload for context
Example response:
GET /api/v1/signals
List recent CAE signals for the current tenant.
limit
Maximum signals to return (default 50, max 500)
Example response:
GET /api/v1/signals/stream
Real-time Server-Sent Events stream for CAE signals. Signals are pushed as they are ingested. Useful for building real-time dashboards or automated response systems.
Example event stream:
OAuth Clients
Register and manage OAuth2 clients (RFC 7591). Clients are global — tenant scoping happens at token issuance, not registration. Use confidential clients (confidential: true) for server-to-server M2M flows; use public PKCE clients for browser or native agent flows.
POST /api/v1/oauth/clients
Register a new OAuth2 client.
client_id
string
Yes
Globally unique client identifier
name
string
Yes
Display name
description
string
No
Human-readable description
confidential
boolean
No
If true, generates a client_secret for M2M flows
token_endpoint_auth_method
string
No
none, client_secret_basic, client_secret_post, private_key_jwt
grant_types
string array
No
Permitted OAuth grant types
scopes
string array
No
Permitted OAuth scopes
redirect_uris
string array
No
Allowed redirect URIs (required for authorization_code clients)
access_token_ttl
integer
No
Access token lifetime in seconds (0 = server default)
refresh_token_ttl
integer
No
Refresh token lifetime in seconds
jwks_uri
string
No
URL to client's public JWK Set (for private_key_jwt)
jwks
JSON object
No
Inline JWK Set (when no URI is available)
software_id
string
No
Client software identifier (RFC 7591)
software_version
string
No
Client software version
contacts
string array
No
Email addresses of responsible parties
metadata
JSON object
No
Arbitrary JSON metadata
Example response:
For public (PKCE) clients the response omits client_secret and the note reads: "Public PKCE client registered — no client_secret (use PKCE code_challenge instead)."
GET /api/v1/oauth/clients
List all registered OAuth2 clients.
Example response:
GET /api/v1/oauth/clients/{id}
Get a single OAuth2 client by its internal UUID (not client_id).
Returns the full client object. client_secret is never included.
DELETE /api/v1/oauth/clients/{id}
Delete an OAuth2 client. Any tokens issued to this client remain valid until their exp claim.
Example response:
POST /api/v1/oauth/clients/{id}/rotate-secret
Rotate a confidential client's secret. The old secret is invalidated immediately. Returns the new plaintext secret — shown once only.
Example response:
Error Responses
Public token endpoints return RFC 6749 §5.2 error bodies:
Admin endpoints return RFC 9457 problem details via Huma:
Common HTTP status codes:
200
Success
201
Resource created
204
Success, no content
400
Bad request — invalid input
401
Unauthorized — missing or invalid credentials
404
Resource not found
409
Conflict — resource already exists
503
Service unavailable — database unreachable
WIMSE Identity URIs
Every identity in ZeroID is assigned a SPIFFE/WIMSE URI used as the JWT sub claim:
Example:
This URI is stable for the lifetime of the identity and is included in every issued JWT, enabling downstream services to make access decisions without calling back to ZeroID.
SDK Reference
The ZeroID SDKs wrap these endpoints with automatic token caching, refresh, and retry logic.
Last updated