For AI agents: a documentation index is available at https://docs.coverbase.com/llms.txt. This page is also available in markdown by appending .md to the URL.
This page covers behavior shared by every public API endpoint. Read it once; the per-resource pages assume it.
Base URLs
All requests are JSON over HTTPS. Every path is versioned under
/v1.
Authentication
Every request must send a bearer token:- Service-account API key (
ak_...): the primary credential for integrations. An admin in your organization mints it on the dashboard’s API keys page (Clerk-backed). It is scoped to exactly one organization; everything the key reads or writes is implicitly scoped to that org. It authenticates as a service account. By default a key carries no scopes and can only call ordinary/v1/*routes; an admin can additionally grant it elevated scopes. A key can do only what the service-account role grants: an endpoint whose permission that role does not hold returns403withapi_key_not_allowed, whether or not your organization enforces custom roles. - OAuth 2.0 access token (
cbat_...): a short-lived token an OAuth client obtains with the client credentials grant. It authenticates as the same service account as anak_*key, carries the client’s elevated scopes, and is accepted wherever anak_*key is. Available to organizations in the third-party lifecycle beta. - Logged-in user JWT: the dashboard session token, useful for first-party scripts running as a specific user. A few endpoint families in this reference accept only this credential and reject
ak_keys: the Bill of Materials API, the Zero Touch Assessments API, the org update andwhoamiendpoints below, and thePOST /v1/<resource>/queryroutes in the field reference. The Import API is the reverse: it accepts onlyak_keys.
ak_* keys self-service via the API Keys API. No support ticket required.
API key scopes
Mostak_* keys carry no scopes: they authenticate ordinary /v1/* calls but cannot reach the admin surfaces. An admin can mint a long-lived key carrying one or more elevated scopes for headless or middleware use:
The key-management and audit-log endpoints accept either a dashboard JWT or an
ak_* key carrying the required scope, so you can run them headlessly without a short-lived session token. Key management requires the org admin role; audit-log reads accept member, siloed member, and admin sessions.
Scopes can only be granted from an admin dashboard session (JWT). A scoped key cannot grant scopes, not to itself and not to another key, so a leaked integration key can never escalate its own access. A request that passes scopes without an admin JWT is rejected with 403 scope_grant_forbidden; a call to a scoped endpoint with a key that lacks the required scope returns 403 insufficient_scope.
There is no unauthenticated surface. A request with no Authorization header returns 403 "Not authenticated". An invalid/expired/revoked key returns 401 "Invalid or expired API key.". A credential whose role is not allowed on the endpoint returns 401 "Unauthorized role.".
Public API audit log
Every call made with anak_* key to a public API resource endpoint (vendors, documents, users, assessments, findings, obligations, radar, reassessments, custom fields, workflows, webhooks, and the Import API) is recorded in the org’s activity log as type=external_api_call with target_type=external_api_request. Each record captures:
- the HTTP method, request path, and matched route template
- the response status code and duration in milliseconds
- the names of query parameters used (values are not recorded)
- the
ak_*key ID and human-readable name that authenticated the request - the client IP and a per-request correlation ID
GET /v1/system_audit_log (and GET /v1/system_audit_log/metadata). Both read endpoints accept either a dashboard session JWT (member, siloed member, or admin) or an ak_* key that carries the audit:read scope.
Requests that fail authentication before the ak_* key resolves (for example, an unknown or revoked key returning 401) are not stored in the activity log; they appear in Coverbase’s structured request logs only and can be retrieved via support if needed for incident response.
Test your credentials
GET /v1/utils/authtest returns 200 and {"msg": "Auth successful"} for any valid token.
cURL
API IP allowlist
An organization can optionally restrict all public API (ak_... key) requests to a set of IPv4/IPv6 CIDRs. This is an org-level control configured by an admin.
-
Default is unrestricted. An empty allowlist (
[], the default) imposes no restriction. -
When configured, a request whose client IP is outside every configured CIDR is rejected with
403: - Fail-closed. If an allowlist is configured but the client IP cannot be determined, the request is denied.
- Scope. The allowlist applies to the public API resource endpoints: vendors (including bank accounts, sites, and other supplier profile data), documents, users, assessments, findings, obligations, radar, reassessments, custom fields, workflows, and webhooks. It does not apply to the API Keys, Intake, Import, and Export endpoints, and it does not affect dashboard sign-in.
-
Client IP source. The connecting IP is the value the Coverbase load balancer appends to
X-Forwarded-For. Clients cannot spoof it by sending their ownX-Forwarded-Forheader.
Configure the allowlist
Set the allowlist from the dashboard (Configuration → Coverbase API → API IP allowlist) or via the org update API. The org update endpoint takes an admin’s dashboard session token; anak_ key can read the org object but cannot change it. Your organization ID is the id field on the org object (also visible in the dashboard).
string[]
A list of CIDR strings (IPv4 or IPv6). Each entry is validated server-side; an invalid CIDR rejects the whole request with
422. An empty list clears the allowlist (unrestricted).Set the allowlist
Read it back
Clear it (unrestricted again)
GET/POST /v1/org/{id}) now includes api_ip_allowlist (a string array; [] when unrestricted). An invalid CIDR returns 422 with a free-form error body (not the coded envelope):
Find your current IP
GET
GET /v1/whoami/ipak_ keys are rejected with 401 Unauthorized role. This is the same value evaluated by the org api_ip_allowlist check, so use it to confirm which IP to allowlist (it backs the dashboard editor’s “Add my current IP” helper).
cURL
string | null
The caller’s source IP.
null if the IP cannot be determined: the same condition under which a configured allowlist fails closed.IDs
Resource IDs are opaque, prefixed strings of the form<prefix>_<32 hex characters> (for example, cbvndr_e448ba62882143f3ba0c140bb2e30162). Treat them as opaque: never parse or construct them.
Findings are internally called “tasks”, so finding IDs use the
cbtask_ prefix. This is expected. A cbtask_... value is a finding ID.Timestamps
Every timestamp is a Unix epoch value in seconds (integer), not milliseconds, not ISO-8601. This applies tocreated_at, updated_at, initiated_at, started_at, completed_at, due_date, occurred_at, and attempted_at.
Idempotency
State-changingPOSTs that support safe retries accept an optional Idempotency-Key request header.
Behavior on supported endpoints: keys are scoped to (org, endpoint, key) and expire 24 hours after first use. The endpoint is the route template, so on the workflow endpoints one key covers every
workflow_name: reusing a key for a different workflow within 24 hours replays the first response. A replay within the window returns the original response body verbatim (same status) and creates nothing new. A replay is never rejected; there is no conflict error. Sending the header to an endpoint that does not support it is harmless but has no effect.
Pagination
List endpoints (GET /v1/vendors, GET /v1/users, GET /v1/portals, GET /v1/findings, GET /v1/obligations, GET /v1/contract-records, GET /v1/engagement-records, and the Radar lists) use limit/offset query parameters:
List responses wrap results as
{ "items": [...], "total": <int>, "limit": <int>, "offset": <int> }. total is the full filtered count (ignoring limit/offset); page until offset + len(items) >= total.
A few lists differ. GET /v1/documents and GET /v1/webhooks/{webhook_id}/deliveries return the page under data instead of items. GET /v1/workflows/runs also uses data, with limit defaulting to 100 and allowed up to 500. GET /v1/reassessments returns every match in one page.
Errors
Application errors use FastAPI’sdetail envelope. Most endpoints return a coded object:
request_id, also sent as the x-coverbase-request-id response header. Quote it when you contact support.
Some endpoints do not use the coded object. POST /v1/assessments creation failures use a free-form error key:
POST /v1/custom-fields/values, the Bill of Materials, Intake, Import, and Export endpoints, and authentication failures return detail as a plain string.
Validation errors
Bodies/params that fail schema validation return422 with FastAPI’s standard array: