API Reference
The Control Zero backend exposes three families of HTTP endpoints:
- SDK endpoints (
/v1/sdk/*) — called by Control Zero SDKs. Authenticated with a project API key (cz_live_*orcz_test_*). - Public API (
/v1/*) — thin, stable surface for programmatic org-level policy management. Authenticated with a project API key. - 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.
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
| Code | Meaning |
|---|---|
200 | Success |
201 | Created |
204 | No content (successful delete) |
304 | Not modified (ETag matched) |
400 | Bad request |
401 | Missing or invalid authentication |
403 | Authenticated but missing scope / role |
404 | Resource not found |
413 | Request body too large |
429 | Rate limit exceeded |
500 | Server error |
503 | Feature 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.
| Method | Path | Purpose |
|---|---|---|
POST | /api/scout/register | Register a Scout agent instance |
POST | /api/scout/heartbeat | Liveness ping |
POST | /api/scout/discoveries | Submit discovered AI surface records |
GET | /api/scout/config | Pull Scout configuration |
POST | /api/scout/license/validate | Validate 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.
| Method | Path | Purpose |
|---|---|---|
POST | /api/enroll | One-time enrollment (no auth; token + pubkey) |
POST | /api/heartbeat | Machine liveness |
GET | /api/policy | Pull policy bundle (machine-signed) |
POST | /api/audit | Submit 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)}`
);
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
| Method | Path | Purpose |
|---|---|---|
GET | / | Root info |
GET | /health | Liveness probe |
GET | /ready | Readiness probe (cache + secrets + auth check) |
These are unauthenticated.
SDKs
For most use cases, use an official SDK instead of calling the API directly:
- Python SDK — canonical SDK with all framework integrations
- Node.js SDK
- Go SDK — core enforcement only
The SDKs handle authentication, ETag-based bundle caching, signature verification, local decryption, audit batching, and retry/backoff.