Skip to main content

API Reference

The Control Zero backend exposes three families of HTTP endpoints:

  1. SDK endpoints (/v1/sdk/*) — called by Control Zero SDKs. Authenticated with a project API key (cz_live_* or cz_test_*).
  2. Public API (/v1/*) — thin, stable surface for programmatic org-level policy management. Authenticated with a project API key.
  3. Dashboard API (/api/*) — powers the Control Zero dashboard. Authenticated with a Firebase ID token (SaaS) or a database-backed JWT session (self-managed). SDK users do not call these directly.

Use the SDK for normal application code. The direct API is useful for custom tooling, CI/CD, and platform integrations.

Base URL

https://api.controlzero.ai

All endpoints are served from this host. There is no /v1 prefix on the base URL itself — individual routes specify their own prefix (/v1/sdk/..., /v1/policies/..., /api/...).

For self-managed deployments, replace the host with your own backend URL.

Authentication

Project API key (SDK + public API)

Endpoints under /v1/sdk/*, /v1/policies*, and /api/scout/* accept a project API key. Keys start with cz_live_ (production) or cz_test_ (test/development).

Two header forms are accepted, either works:

# Preferred
curl -H "X-API-Key: cz_live_..." \
https://api.controlzero.ai/v1/sdk/bootstrap

# Also accepted
curl -H "Authorization: Bearer cz_live_..." \
https://api.controlzero.ai/v1/sdk/bootstrap

A request missing a valid API key returns 401 MISSING_API_KEY. A key that does not start with cz_live_ or cz_test_ returns 401 INVALID_API_KEY_FORMAT. An unknown key returns 401 INVALID_API_KEY.

Gateway uses a different header name

The backend at api.controlzero.ai accepts X-API-Key or Authorization: Bearer. The hosted gateway at gateway.controlzero.ai accepts X-ControlZero-API-Key or Authorization: Bearer instead (to avoid colliding with the upstream provider's X-Api-Key header, e.g. Anthropic). If you are calling the gateway directly, use X-ControlZero-API-Key. If you are calling the backend, use X-API-Key.

Scopes

API keys carry scopes (read, write, scout). SDK endpoints require at least read. Mutating public-API endpoints require write. Scout endpoints require scout. A key without the required scope returns 403 FORBIDDEN_SCOPE.

Dashboard auth (/api/*)

Dashboard endpoints authenticate with a Firebase ID token (SaaS mode) or a JWT session token (self-managed mode). These endpoints are intended for the Control Zero dashboard frontend. SDK users should not call them directly; there is no stable public contract.

Event stream query param

The SSE stream at /api/events/stream also accepts an access_token query parameter, because browsers cannot set custom headers on EventSource. This is the only endpoint that accepts a key via query string.

Request format

  • Request bodies must be JSON with Content-Type: application/json.
  • Request bodies are capped at 1 MB. Oversized requests return 413 Request Entity Too Large.
  • Responses are JSON unless otherwise noted (policy bundles are binary application/octet-stream).
  • Timestamps are ISO 8601 in UTC.

HTTP status codes

CodeMeaning
200Success
201Created
204No content (successful delete)
304Not modified (ETag matched)
400Bad request
401Missing or invalid authentication
403Authenticated but missing scope / role
404Resource not found
413Request body too large
429Rate limit exceeded
500Server error
503Feature disabled or dependency unavailable

Error format

{
"error": {
"code": "INVALID_API_KEY",
"message": "invalid API key"
}
}

Rate limiting

Every authenticated path runs behind a combined IP + API-key rate limiter:

  • 1000 requests / minute per source IP (DDoS guard)
  • 500 requests / minute per API key (tenant abuse guard)

When the limit is exceeded, the server returns 429 Too Many Requests. Clients should back off with exponential retry. Rate limit state is keyed in an in-memory cache; limits are shared across backend instances.

SDK endpoints (/v1/sdk/*)

All SDK endpoints require a project API key with read scope (plus any per-endpoint scope noted below). They are what the Python, Node, and Go SDKs call under the hood.

POST /v1/sdk/init

Declares the SDK session on startup. Used for session tracking and usage metering.

curl -X POST https://api.controlzero.ai/v1/sdk/init \
-H "X-API-Key: cz_live_..." \
-H "Content-Type: application/json" \
-d '{"sdk_version": "1.4.0", "agent_id": "agent-001"}'

POST /v1/sdk/logs

Submits a batch of local audit log entries for ingest into the governance audit trail. Used by SDKs in hybrid mode.

curl -X POST https://api.controlzero.ai/v1/sdk/logs \
-H "X-API-Key: cz_live_..." \
-H "Content-Type: application/json" \
-d '{"entries": [ { "tool": "llm", "method": "generate", "decision": "allow", "timestamp": "2026-04-15T12:00:00Z" } ]}'

POST /v1/sdk/refresh

Refreshes the SDK session handle.

GET /v1/sdk/bootstrap

Returns the hosted-mode bootstrap payload: the org's signing public key and the project's encryption key material needed to verify and decrypt a signed policy bundle.

curl -H "X-API-Key: cz_live_..." \
https://api.controlzero.ai/v1/sdk/bootstrap

Response (200):

{
"project_id": "proj_...",
"org_id": "org_...",
"signing_public_key": "<base64-encoded verification pubkey>",
"project_encryption_key": "<base64 key>",
"bundle_url": "/v1/sdk/policies/pull"
}

GET /v1/sdk/policies/pull

Returns the signed + encrypted policy bundle for the caller's project. Supports ETag-based conditional requests: pass If-None-Match with the last seen ETag and receive 304 Not Modified when the bundle is unchanged.

Response content type is application/octet-stream. The body is a binary .czpolicy blob; the SDK verifies the signature and decrypts it in-process.

curl -H "X-API-Key: cz_live_..." \
-H "If-None-Match: \"v17\"" \
https://api.controlzero.ai/v1/sdk/policies/pull \
--output policy.czpolicy

GET /v1/sdk/keys/public

Returns the org's verification public key used to verify policy bundle signatures. Typically called once during SDK bootstrap and cached.

POST /v1/sdk/audit

Hosted-mode audit ingest. Accepts decision records from the SDK and writes them to the audit trail.

POST /v1/sdk/tamper-alert

Reports a tamper detection event (signature verification failure, bundle decryption failure, or quarantine trigger). The backend records the alert and may escalate per the org's tamper_behavior setting.

Request body:

{
"machine_id": "machine-abc",
"event_type": "signature_invalid",
"context": { "bundle_version": "v17" },
"timestamp": "2026-04-15T12:00:00Z"
}

Public API (/v1/*)

The public API currently exposes one resource: policies. This is stable surface area intended for CI/CD and custom tooling.

GET /v1/policies

List policies across the caller's org. Requires read scope.

curl -H "X-API-Key: cz_live_..." https://api.controlzero.ai/v1/policies

Response (200):

{
"policies": [
{
"id": "policy_...",
"name": "model-governance",
"version": 3,
"org_id": "org_...",
"project_id": "proj_...",
"updated_at": "2026-04-01T09:00:00Z"
}
]
}

POST /v1/policies

Create a new policy. Requires write scope.

PATCH /v1/policies/{policyID}

Update a policy in place. Requires write scope.

DELETE /v1/policies/{policyID}

Delete a policy. Requires write scope. Returns 204 on success.

Scout API (/api/scout/*)

The Shadow AI Scout discovery agent uses this endpoint family. Requires an API key with scout scope.

MethodPathPurpose
POST/api/scout/registerRegister a Scout agent instance
POST/api/scout/heartbeatLiveness ping
POST/api/scout/discoveriesSubmit discovered AI surface records
GET/api/scout/configPull Scout configuration
POST/api/scout/license/validateValidate an on-prem Scout license

Machine-signed SDK endpoints (enrollment mode)

When the SDK is enrolled against the backend with a signing keypair (rather than an API key), it calls these endpoints. Each request carries a per-request cryptographic signature verified by the MachineAuth middleware. No bearer token travels on the wire.

MethodPathPurpose
POST/api/enrollOne-time enrollment (no auth; token + pubkey)
POST/api/heartbeatMachine liveness
GET/api/policyPull policy bundle (machine-signed)
POST/api/auditSubmit audit events (machine-signed)

Enrollment is gated behind the ENROLLMENT_API_ENABLED flag; when disabled these routes return 503 FEATURE_DISABLED.

Dashboard API (/api/*)

The dashboard endpoints are documented here for reference only. They authenticate with a Firebase ID token (SaaS) or a database-backed JWT session (self-managed). SDK users should not rely on these; their URLs and payloads may change without notice.

The canonical resource path layout is:

/api/orgs/{orgID}
/api/orgs/{orgID}/members
/api/orgs/{orgID}/projects
/api/orgs/{orgID}/policies # all policies across projects
/api/orgs/{orgID}/settings
/api/orgs/{orgID}/dlp/rules
/api/orgs/{orgID}/sso
/api/orgs/{orgID}/enrollment-tokens
/api/orgs/{orgID}/fleet
/api/orgs/{orgID}/coverage
/api/orgs/{orgID}/notifications
/api/orgs/{orgID}/browser-extension
/api/orgs/{orgID}/compliance/browser-ext-ack

/api/projects/{projectID}
/api/projects/{projectID}/api-keys
/api/projects/{projectID}/tools
/api/projects/{projectID}/secrets
/api/projects/{projectID}/policies
/api/projects/{projectID}/keys # key provisioning / rotation
/api/projects/{projectID}/tamper-alerts
/api/projects/{projectID}/logs # audit log query
/api/projects/{projectID}/analytics
/api/projects/{projectID}/anomalies
/api/projects/{projectID}/compliance
/api/projects/{projectID}/mcp # hosted MCP provisioning
/api/projects/{projectID}/scout

Dashboard write operations require a CSRF token from GET /api/csrf-token in addition to the bearer auth header. This is not relevant to SDK callers.

A separate admin tree lives at /api/admin/* and requires an additional admin role check.

Live event stream (SSE)

GET /api/events/stream

Server-Sent Events stream of governance decisions. Accepts the project API key as X-API-Key, Authorization: Bearer, or (only here) ?access_token= query param. Each event is a JSON object:

{
"id": "...",
"type": "decision",
"agent": "...",
"tool": "...",
"policy": "...",
"latency_ms": 12,
"timestamp": "..."
}
const es = new EventSource(
`https://api.controlzero.ai/api/events/stream?access_token=${encodeURIComponent(CZ_API_KEY)}`
);
Security trade-off

Query-string tokens can leak through browser history, referrer headers, and reverse-proxy access logs. Query-param auth is scoped to this one route. Anywhere else, use the X-API-Key or Authorization header.

SSO / SCIM / SAML

Enterprise SSO endpoints live at /scim/v2/* (SCIM 2.0 user provisioning, bearer token auth) and /saml/{orgID}/* (SAML 2.0 SP). These are Teams-tier features, configured per-org via /api/orgs/{orgID}/sso. See the SSO setup guide for details.

Health

MethodPathPurpose
GET/Root info
GET/healthLiveness probe
GET/readyReadiness probe (cache + secrets + auth check)

These are unauthenticated.

SDKs

For most use cases, use an official SDK instead of calling the API directly:

The SDKs handle authentication, ETag-based bundle caching, signature verification, local decryption, audit batching, and retry/backoff.