Skip to main content
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:
Two credential types are accepted:
  • 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 returns 403 with api_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 an ak_* key, carries the client’s elevated scopes, and is accepted wherever an ak_* 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 and whoami endpoints below, and the POST /v1/<resource>/query routes in the field reference. The Import API is the reverse: it accepts only ak_ keys.
Admins can list, create, rotate, and revoke ak_* keys self-service via the API Keys API. No support ticket required.

API key scopes

Most ak_* 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:
banking:read and review:sensitive_changes are the two scopes worth pausing on. The first lets a key read account numbers in full; the second lets a key bypass the human review that a bank-detail change would otherwise wait for. Both are deliberate, admin-minted and revocable, and neither is granted by default. Leave them off unless a specific integration genuinely needs them, and see Data protection for what is masked without them.
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 an ak_* 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
Request and response bodies are not stored, with one exception: a call to a custom Import API report stores both bodies, redacted and capped at 1 MB, and shows them on that report’s Request history tab. The records surface in the dashboard under Configuration → Audit Logs (in the Integrations group) and through 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 own X-Forwarded-For header.

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; an ak_ 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)
The org object (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):
Add the egress IPs of your integration before enabling the allowlist, and keep a dashboard admin path available: a too-narrow allowlist locks every API client out until it is widened or cleared from the dashboard.

Find your current IP

GET
GET /v1/whoami/ip
A convenience endpoint that returns the caller’s source IP as the API sees it: the load-balancer-appended, unspoofable value. It takes a dashboard session token; ak_ 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 to created_at, updated_at, initiated_at, started_at, completed_at, due_date, occurred_at, and attempted_at.

Idempotency

State-changing POSTs 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.
Use a stable identifier from the source system (a procurement request ID, a ticket number) as the idempotency key so source-side retries deduplicate naturally.

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’s detail envelope. Most endpoints return a coded object:
Every error body carries a 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 return 422 with FastAPI’s standard array:

Common status codes