> ## Documentation Index
> Fetch the complete documentation index at: https://docs.coverbase.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Monitoring and insights API

> Read Inspect applications, inspections and schedules, document insights, document insight review items, dark web exposures, and vendor certificates, and pause or resume Inspect schedules.

For AI agents: a documentation index is available at [https://docs.coverbase.com/llms.txt](https://docs.coverbase.com/llms.txt). This page is also available in markdown by appending .md to the URL.

These endpoints give you API access to four monitoring features: Inspect schedules (internal controls monitoring), the document insight review queue, dark web monitoring, and the Certificate Vault.

All endpoints are scoped to the API key's organization. See [API conventions](/conventions.md) for shared behavior. List endpoints take `limit` and `offset` and return `items`, `total`, `limit`, and `offset`.

| Method | Path | Permission |
| - | - | - |
| `GET` | `/v1/inspect-schedules` | `integration:read:org` |
| `POST` | `/v1/inspect-schedules/{schedule_id}/pause` | `integration:run:org` |
| `POST` | `/v1/inspect-schedules/{schedule_id}/resume` | `integration:run:org` |
| `GET` | `/v1/document-insight-pending-changes` | `vendor:read:org` |
| `GET` | `/v1/dark-web/summary` | `dark_web_exposure:read:org` |
| `GET` | `/v1/dark-web/exposures` | `dark_web_exposure:read:org` |
| `GET` | `/v1/vendor-certificates` | `vendor:read:org` |
| `GET` | `/v1/inspect-applications` | `integration:read:org` |
| `POST` | `/v1/inspect-schedules` | `integration:run:org` |
| `PATCH` | `/v1/inspect-schedules/{schedule_id}` | `integration:run:org` |
| `DELETE` | `/v1/inspect-schedules/{schedule_id}` | `integration:run:org` |
| `POST` | `/v1/document-insights` | `org_settings:update:org` |
| `POST` | `/v1/document-insights/{config_id}/archive` | `org_settings:update:org` |
| `POST` | `/v1/document-insights/{config_id}/restore` | `org_settings:update:org` |
| `PATCH` | `/v1/document-insights/{config_id}` | `org_settings:update:org` |
| `POST` | `/v1/document-insights/bulk-update` | `org_settings:update:org` |
| `POST` | `/v1/document-insights/bulk-archive` | `org_settings:update:org` |
| `GET` | `/v1/document-insight-models` | `vendor:read:org` |
| `GET` | `/v1/document-insight-definitions` | `vendor:read:org` |
| `POST` | `/v1/document-insight-definitions` | `org_settings:update:org` |
| `POST` | `/v1/document-insight-definitions/test` | `org_settings:update:org` |
| `POST` | `/v1/document-insight-models` and its `dataset`, `evaluate`, `training`, `training/sync`, `activate`, and `retire` actions | `org_settings:update:org` |
| `GET` | `/v1/document-insights/{config_id}/promotion-options` | `custom_field:read:org` |
| `POST` | `/v1/document-insights/{config_id}/promote` | `custom_field:update:org` |
| `DELETE` | `/v1/document-insights/{config_id}/custom-fields/{custom_field_id}` | `custom_field:update:org` |
| `GET` | `/v1/document-insights/{config_id}/targets` | `vendor:read:org` |
| `POST` | `/v1/document-insights/{config_id}/targets` | `org_settings:update:org` |
| `PATCH` | `/v1/document-insight-targets/{target_id}` | `org_settings:update:org` |
| `DELETE` | `/v1/document-insight-targets/{target_id}` | `org_settings:update:org` |
| `GET` | `/v1/document-insight-stats` | `vendor:read:org` |
| `GET` | `/v1/document-insight-groups` | `vendor:read:org` |
| `POST` | `/v1/document-insight-groups` | `org_settings:update:org` |
| `PATCH` | `/v1/document-insight-groups/{group_id}` | `org_settings:update:org` |
| `DELETE` | `/v1/document-insight-groups/{group_id}` | `org_settings:update:org` |
| `GET` | `/v1/dark-web/config` | `dark_web_exposure:read:org` |
| `PATCH` | `/v1/dark-web/config` | `dark_web_exposure:update:org` |
| `PATCH` | `/v1/dark-web/exposures/{exposure_id}/review` | `dark_web_exposure:update:org` |
| `GET` | `/v1/dark-web/watchlist` | `dark_web_exposure:read:org` |
| `POST` | `/v1/dark-web/watchlist` | `dark_web_exposure:update:org` |
| `PATCH` | `/v1/dark-web/watchlist/{asset_id}` | `dark_web_exposure:update:org` |
| `DELETE` | `/v1/dark-web/watchlist/{asset_id}` | `dark_web_exposure:update:org` |
| `GET` | `/v1/dark-web/playbooks` | `dark_web_exposure:read:org` |
| `PUT` | `/v1/dark-web/playbooks/{key}` | `dark_web_exposure:update:org` |
| `DELETE` | `/v1/dark-web/playbooks/{key}` | `dark_web_exposure:update:org` |
| `POST` | `/v1/vendor-certificates` | `vendor:update:org` |
| `PATCH` | `/v1/vendor-certificates/{certificate_id}/verification` | `vendor:update:org` |
| `DELETE` | `/v1/vendor-certificates/{certificate_id}` | `vendor:update:org` |
| `POST` | `/v1/vendor-certificate-requests` | `vendor:update:org`, `portal:create:org` |
| `GET` | `/v1/certificate-renewal-jobs` | `vendor:read:org` |
| `POST` | `/v1/certificate-renewal-jobs` | `vendor:update:org`, `portal:create:org` |
| `GET` | `/v1/certificate-renewal-jobs/{job_id}` | `vendor:read:org` |
| `POST` | `/v1/certificate-networks/{network}/sync` | `integration:run:org` |
| `GET` | `/v1/prequalification-rule-sets` | `vendor:read:org` |
| `POST` | `/v1/prequalification-rule-sets` | `vendor:update:org` |
| `PUT` | `/v1/prequalification-rule-sets/{rule_set_id}` | `vendor:update:org` |
| `DELETE` | `/v1/prequalification-rule-sets/{rule_set_id}` | `vendor:update:org` |
| `GET` | `/v1/vendors/{vendor_id}/prequalification` | `vendor:read:org` |
| `POST` | `/v1/vendors/{vendor_id}/prequalification/refresh` | `vendor:update:org` |
| `GET` | `/v1/vendors/{vendor_id}/security-benchmark` | `vendor:read:org` |
| `POST` | `/v1/vendor-certificates/query` | `vendor:read:org` |
| `GET` | `/v1/certificate-networks` | `vendor:read:org` |
| `POST` | `/v1/vendors/{vendor_id}/external-security/rescan` | `vendor:update:org` |
| `POST` | `/v1/vendors/{vendor_id}/external-security/estate-reviews` | `vendor:update:org` |
| `POST` | `/v1/vendors/{vendor_id}/external-security/estate-assets` | `vendor:update:org` |
| `GET` | `/v1/vendors/{vendor_id}/external-security/peers` | `vendor:read:org` |
| `POST` | `/v1/vendors/{vendor_id}/external-security/peers/refresh` | `vendor:read:org`, or `vendor:update:org` with `force` |
| `GET` | `/v1/vendor-scan-results` | `vendor:read:org` |
| `GET` | `/v1/vendor-scan-results/{scan_result_id}` | `vendor:read:org` |
| `POST` | `/v1/document-insight-values/{data_id}/accept` | `vendor:update:org` |
| `POST` | `/v1/document-insight-values/{data_id}/verdict` | `vendor:update:org` |
| `POST` | `/v1/document-insight-values/{data_id}/to-example` | `org_settings:update:org` |
| `GET` | `/v1/document-insights/{config_id}/examples` | `vendor:read:org` |
| `POST` | `/v1/document-insights/{config_id}/examples` | `org_settings:update:org` |
| `PATCH` | `/v1/document-insight-examples/{example_id}` | `org_settings:update:org` |
| `DELETE` | `/v1/document-insight-examples/{example_id}` | `org_settings:update:org` |
| `POST` | `/v1/document-insight-backfills/preview` | `vendor:read:org` |
| `POST` | `/v1/document-insight-backfills` | `org_settings:update:org` |
| `GET` | `/v1/document-insight-backfills` | `vendor:read:org` |
| `GET` | `/v1/document-insight-backfills/{backfill_id}` | `vendor:read:org` |
| `POST` | `/v1/document-insight-backfills/{backfill_id}/cancel` | `org_settings:update:org` |
| `POST` | `/v1/dark-web/exposures/{exposure_id}/escalate` | `dark_web_exposure:update:org` |
| `POST` | `/v1/dark-web/watchlist/sync` | `dark_web_exposure:update:org` |
| `GET` | `/v1/dark-web/retention` | `dark_web_exposure:read:org` |
| `PUT` | `/v1/dark-web/retention` | `dark_web_exposure:update:org`, `org_settings:update:org` |
| `GET` | `/v1/org-documents` | `vendor:read:org` |
| `GET` | `/v1/org-documents/{document_id}/download` | `vendor:export:org` |
| `PATCH` | `/v1/org-documents/{document_id}` | `vendor:update:org` |
| `POST` | `/v1/org-documents` | `vendor:update:org` |
| `POST` | `/v1/document-insight-values/{data_id}/correct` | `vendor:update:org` |
| `DELETE` | `/v1/document-insight-values/{data_id}` | `vendor:update:org` |
| `POST` | `/v1/document-insight-values/bulk-verdict` | `vendor:update:org` |
| `GET` | `/v1/inspections` | `integration:read:org` |
| `GET` | `/v1/document-insights` | `vendor:read:org` |
| `GET` | `/v1/document-insight-values` | `vendor:read:org` |
| `POST` | `/v1/inspect-applications` | `integration:update:org` |
| `POST` | `/v1/inspect-applications/bulk` | `integration:update:org` |
| `GET` | `/v1/inspect-applications/{application_id}` | `integration:read:org` |
| `PATCH` | `/v1/inspect-applications/{application_id}` | `integration:update:org` |
| `PUT` | `/v1/inspect-applications/{application_id}/vendor` | `integration:update:org` |
| `PUT` | `/v1/inspect-applications/{application_id}/platform` | `integration:update:org` |
| `POST` | `/v1/inspect-applications/link-suggested-vendors` | `integration:update:org` |
| `POST` | `/v1/inspect-applications/{application_id}/archive` | `integration:update:org` |
| `POST` | `/v1/inspect-applications/{application_id}/unarchive` | `integration:update:org` |
| `POST` | `/v1/inspect-applications/bulk-archive` | `integration:update:org` |
| `DELETE` | `/v1/inspect-applications/{application_id}` | `integration:update:org` |
| `GET` | `/v1/inspect-setup-options` | `integration:read:org` |
| `GET` | `/v1/inspect-platforms` | `integration:read:org` |
| `GET` | `/v1/inspect-applications/{application_id}/config` | `integration:read:org` |
| `PATCH` | `/v1/inspect-applications/{application_id}/config` | `integration:update:org` |
| `GET` | `/v1/inspect-plans/readiness` | `integration:read:org` |
| `POST` | `/v1/inspect-plans/ensure` | `integration:run:org` |
| `GET` | `/v1/inspect-plans/{plan_id}` | `integration:read:org` |
| `GET` | `/v1/inspect-plans/{plan_id}/versions` | `integration:read:org` |
| `POST` | `/v1/inspect-plans/{plan_id}/revisions/validate` | `integration:update:org` |
| `POST` | `/v1/inspect-plans/{plan_id}/revisions` | `integration:update:org` |
| `POST` | `/v1/inspect-plans/{plan_id}/regenerate` | `integration:update:org` |
| `POST` | `/v1/inspect-plans/{plan_id}/requirements/{requirement_key}/regenerate` | `integration:update:org` |
| `POST` | `/v1/inspections` | `integration:run:org` |
| `POST` | `/v1/inspections/query` | `integration:read:org` |
| `GET` | `/v1/inspections/{inspection_id}` | `integration:read:org` |
| `POST` | `/v1/inspections/bulk-archive` | `integration:update:org`, `integration:archive:org` |
| `POST` | `/v1/inspections/bulk-cancel` | `integration:run:org` |
| `POST` | `/v1/inspections/{inspection_id}/runs/bulk-cancel` | `integration:run:org` |
| `POST` | `/v1/inspections/{inspection_id}/runs/bulk-retry` | `integration:run:org` |
| `GET` | `/v1/inspect-posture` | `integration:read:org` |
| `GET` | `/v1/inspect-summary` | `integration:read:org` |
| `GET` | `/v1/inspect-identities/summary` | `integration:read:org` |
| `POST` | `/v1/inspect-identities/query` | `integration:read:org` |
| `PUT` | `/v1/inspect-accounts/owner` | `integration:update:org` |
| `POST` | `/v1/inspect-identities/merge` | `integration:update:org` |
| `PUT` | `/v1/inspect-idp-applications/{application_id}/platform` | `integration:update:org` |
| `GET` | `/v1/inspect-auth-contexts` | `integration:read:org` |
| `POST` | `/v1/inspect-auth-contexts` | `integration:update:org` |
| `POST` | `/v1/inspect-auth-contexts/{auth_context_id}/stale` | `integration:update:org` |
| `POST` | `/v1/inspect-documentation-discovery-runs` | `integration:run:org` |
| `GET` | `/v1/inspect-documentation-discovery-runs/{run_id}` | `integration:read:org` |
| `GET` | `/v1/inspect-applications/{application_id}/documentation` | `integration:read:org` |
| `GET` | `/v1/okta-integration/applications` | `integration:read:org` |
| `GET` | `/v1/entra-integration/applications` | `integration:read:org` |
| `GET` | `/v1/okta-integration/schedule` | `integration:read:org` |
| `PUT` | `/v1/okta-integration/schedule` | `integration:update:org`, organization admin |
| `GET` | `/v1/okta-integration/sync` | `integration:read:org` |
| `DELETE` | `/v1/okta-integration` | `integration:update:org`, organization admin |
| `GET` | `/v1/inspections/{inspection_id}/runs/{run_id}/replay` | `integration:read:org` |
| `GET` | `/v1/inspections/{inspection_id}/runs/{run_id}/replay/pages/{page_id}` | `integration:read:org` |
| `GET` | `/v1/inspections/{inspection_id}/runs/{run_id}/live-view` | `integration:read:org` |
| `POST` | `/v1/inspect-probes/prepare` | `integration:update:org` |
| `GET` | `/v1/inspect-probes` | `integration:read:org` |
| `POST` | `/v1/inspect-probes/query` | `integration:read:org` |
| `POST` | `/v1/inspect-probes` | `integration:update:org` |
| `GET` | `/v1/inspect-probes/{probe_id}` | `integration:read:org` |
| `POST` | `/v1/inspect-probes/{probe_id}/versions` | `integration:update:org` |
| `PATCH` | `/v1/inspect-probes/{probe_id}/automation` | `integration:run:org` |
| `POST` | `/v1/inspect-probes/{probe_id}/preview` | `integration:run:org` |
| `GET` | `/v1/inspect-probes/{probe_id}/runs` and `/runs/{run_id}` | `integration:read:org` |
| `GET` | `/v1/inspect-probes/{probe_id}/runs/{run_id}/package` | `integration:read:org` |
| `GET` | `/v1/inspect-probes/{probe_id}/deliveries` | `integration:read:org` |
| `GET` | `/v1/inspect-probes/definitions` and `/definitions/{definition_id}` (deprecated) | `integration:read:org` |
| `POST` | `/v1/inspect-probes/definitions/{definition_id}/prepare-binding` (deprecated) | `integration:update:org` |
| `POST` | `/v1/okta-integration/sync` | `integration:run:org`, organization admin |
| `POST` | `/v1/okta-integration/verify` | `integration:run:org`, organization admin |
| `GET` | `/v1/okta-integration/scopes` | `integration:read:org` |
| `GET` | `/v1/okta-integration/applications/{application_id}` and `/users` | `integration:read:org` |
| `GET` | `/v1/okta-integration/identities` and `/identities/summary` | `integration:read:org` |
| `GET` | `/v1/okta-integration/inspection-identity` | `integration:read:org` |
| `POST` | `/v1/okta-integration/provision` | `integration:update:org`, organization admin |
| `POST` | `/v1/okta-integration/deprovision` | `integration:update:org`, organization admin |
| `POST` | `/v1/okta-integration/inspect-runs` | `integration:run:org`, organization admin |
| `GET` | `/v1/okta-integration/inspect-runs/{run_id}` | `integration:read:org` |
| `POST` | `/v1/entra-integration/verify` | `integration:run:org`, organization admin |
| `POST` | `/v1/entra-integration/sync` | `integration:run:org`, organization admin |
| `POST` | `/v1/entra-integration/provision` | `integration:update:org`, organization admin |
| `GET` | `/v1/entra-integration/inspection-identity` | `integration:read:org` |
| `GET` | `/v1/inspect-identities/{identity_id}` | `integration:read:org` |
| `GET` | `/v1/inspect-identities/{identity_id}/events` | `integration:read:org` |
| `GET` | `/v1/inspect-identities/{identity_id}/accounts/{account_id}/evidence` | `integration:read:org` |
| `GET` | `/v1/inspect-account-applications` | `integration:read:org` |
| `GET` | `/v1/inspect-credentials` | `integration:read:org` |
| `POST` | `/v1/inspect-identities/reconcile` | `integration:run:org`, organization admin |
| `GET` | `/v1/inspect-identities/reconcile/{request_id}` | `integration:read:org` |
| `POST` | `/v1/inspect-auth-contexts/{auth_context_id}/bootstrap` | `integration:run:org` |
| `POST` | `/v1/inspect-evaluations/{evaluation_id}/finding` | `finding:create:org` |
| `POST` | `/v1/findings/{finding_id}/recommended-remediation/draft` | `finding:update:org` |
| `GET` | `/v1/findings/{finding_id}/recommended-remediation` | `finding:read:org` |
| `GET` | `/v1/inspect-applications/{application_id}/documentation/{document_key}` | `integration:read:org` |
| `GET` | `/v1/inspect-events` | `integration:read:org` |
| `POST` | `/v1/access-removal-requests/{request_id}/reject` and `/complete-manually` | `integration:update:org` |
| `GET` | `/v1/document-insights/{config_id}/delete-preview` | `vendor:read:org` |
| `DELETE` | `/v1/document-insights/{config_id}` | `org_settings:update:org` |
| `GET` | `/v1/document-insights/{config_id}/events` | `vendor:read:org` |
| `GET` | `/v1/document-insights/{config_id}/revisions` | `vendor:read:org` |
| `GET` | `/v1/document-insight-values/{data_id}/events` | `vendor:read:org` |
| `GET` | `/v1/document-insight-coverage` | `vendor:read:org` |
| `POST` | `/v1/document-insight-values/query` | `vendor:read:org` |
| `POST` | `/v1/document-insight-values/pivot` | `vendor:read:org` |
| `GET` | `/v1/document-insight-values/{data_id}/snippets` | `vendor:read:org` |
| `POST` | `/v1/document-insight-values/{data_id}/snippets` | `vendor:read:org` |
| `GET` | `/v1/document-insight-export-columns` | `vendor:read:org` |
| `POST` | `/v1/document-insights/{config_id}/export` | `vendor:export:org` |
| `GET` | `/v1/document-insight-models/{model_id}/scorecard`, `/examples`, and `/dataset-preview` | `vendor:read:org` |
| `PUT` | `/v1/document-insight-models/{model_id}/shadow` | `org_settings:update:org` |
| `POST` | `/v1/document-insight-eval-examples/{example_id}/review` | `org_settings:update:org`, and `vendor:update` on the vendor for `ai_right` |
| `POST` | `/v1/documents/{document_id}/insight-extractions` | `vendor:update:org` |
| `POST` | `/v1/documents/{document_id}/insight-previews` | `vendor:read:org` |
| `GET` | `/v1/document-insight-previews/{job_id}` | `vendor:read:org` |
| `GET` | `/v1/document-insight-target-fields` | `vendor:read:org` |
| `GET` | `/v1/document-insight-inbox` | `vendor:read:org` |
| `POST` | `/v1/document-insight-pending-changes/{change_id}/reject` | `org_settings:update:org`, or the assigned reviewer |
| `GET` | `/v1/document-type-decision-model` | `org_settings:read:org` |
| `POST` | `/v1/document-type-decision-model/train-fork` | `org_settings:update:org` |
| `GET` | `/v1/dark-web/exposures/{exposure_id}` and `/history` | `dark_web_exposure:read:org` |
| `GET` | `/v1/dark-web/exposures/{exposure_id}/playbook` | `dark_web_exposure:read:org` |
| `PATCH` | `/v1/dark-web/exposures/{exposure_id}/playbook` | `dark_web_exposure:update:org` |
| `POST` | `/v1/dark-web/exposures/bulk-review` | `dark_web_exposure:update:org` |
| `GET` | `/v1/dark-web/exposures/{exposure_id}/evidence` | `dark_web_exposure:evidence:org` |
| `POST` | `/v1/dark-web/exposures/{exposure_id}/partner-follow-up` | `dark_web_exposure:update:org` |
| `POST` | `/v1/dark-web/exposures/export` | `dark_web_exposure:export:org` |
| `GET` | `/v1/dark-web/access` | `role:read:org` |
| `POST` | `/v1/dark-web/access/roles` | `role:create:org` |
| `GET` | `/v1/dark-web/retention/preview` | `dark_web_exposure:update:org` |
| `GET` | `/v1/dark-web/setup` | `dark_web_exposure:read:org` |
| `POST` | `/v1/dark-web/setup/confirm/{confirmation}` | `dark_web_exposure:update:org` |
| `POST` | `/v1/dark-web/baseline/preview` and `/v1/dark-web/baseline/import` | `dark_web_exposure:update:org` |
| `GET` | `/v1/dark-web/baseline` | `dark_web_exposure:read:org` |
| `GET` | `/v1/dark-web/report` | `dark_web_exposure:report:org` or `dark_web_exposure:read:org` |
| `POST` | `/v1/dark-web/sweeps` | `dark_web_exposure:run:org` |
| `GET` | `/v1/dark-web/sweeps` | `dark_web_exposure:read:org` |
| `GET` | `/v1/dark-web/vendors/{vendor_id}` | `dark_web_exposure:read:org` |
| `GET` | `/v1/dark-web/ai-fraud-terms` | `dark_web_exposure:read:org` |
| `GET` | `/v1/dark-web/sources` | `dark_web_exposure:read:org` |
| `GET` | `/v1/dark-web/alert-rules` | `dark_web_exposure:read:org` |
| `POST` | `/v1/dark-web/alert-rules` | `dark_web_exposure:update:org`, organization admin |
| `PATCH` | `/v1/dark-web/alert-rules/{rule_id}` | `dark_web_exposure:update:org`, organization admin |
| `PUT` | `/v1/dark-web/alert-rules/order` | `dark_web_exposure:update:org`, organization admin |
| `POST` | `/v1/dark-web/alert-rules/preview` | `dark_web_exposure:read:org` |
| `POST` | `/v1/dark-web/alert-rules/test` | `dark_web_exposure:update:org`, organization admin |

Routes that need a `dark_web_exposure` permission, a `role` permission, or `org_settings:update:org` work with a user API key only. Service account keys do not hold those permissions, so use a key created by a person whose role holds them.

Each feature has its own gate. When your organization does not have the feature, its endpoints return `404` with one of these codes:

| Code | Feature |
| - | - |
| `inspect_not_enabled` | Inspect |
| `dark_web_not_enabled` | Dark web monitoring |
| `certificates_not_enabled` | Certificate Vault |

When your organization enforces roles and the key lacks the permission, the endpoint returns `403`.

Some actions stay with a signed-in person. When an API key calls one of them, the endpoint returns `403` with the code `api_key_not_allowed`. These actions are: archiving or restoring a document insight (one at a time or in bulk), unlinking a custom field from an insight, resetting a dark web playbook, retiring a decision model, deleting an insight group or target, stopping an Inspect schedule, removing a watchlist identifier, marking a certificate `verified`, archiving a certificate, archiving a rule set, deleting an insight example or value, archiving or restoring an org document, deleting a document insight, rejecting a pending change, creating dark web roles, confirming a dark web setup step, provisioning or deprovisioning an Okta or Entra inspection identity, and rejecting or manually completing an access removal request. API keys never change roles.

## List Inspect schedules

**method** `GET`

`GET /v1/inspect-schedules`

Returns your recurring Inspect schedules, newest first. A schedule inspects one application against its control sets on a day of the month or at a fixed interval.

**include\_archived** `boolean` (default: false)

Set to `true` to include stopped schedules.

**limit** `integer` (default: 20)

Page size, from 1 to 100.

**offset** `integer` (default: 0)

Number of schedules to skip.

### Response

**items** `object[]`

**schedule**

**id** `string`

Schedule ID.

**target\_id** `string | null`

The application the schedule inspects.

**app\_name** `string | null`

The application's display name.

**control\_set\_ids** `string[]`

Control sets each inspection checks.

**purpose** `string`

`evaluative`, `exploratory`, or `drift`.

**day\_of\_month** `integer | null`

Day of the month a monthly schedule runs.

**interval\_seconds** `integer | null`

Seconds between runs for an interval schedule.

**is\_paused** `boolean`

Whether the schedule is paused.

**is\_archived** `boolean`

Whether the schedule is stopped.

**created\_at** `integer`

Unix timestamp.

## Pause or resume an Inspect schedule

**method** `POST`

`POST /v1/inspect-schedules/{schedule_id}/pause`

**method** `POST`

`POST /v1/inspect-schedules/{schedule_id}/resume`

To stop a schedule from starting inspections for a while, pause it. To start it again, resume it. Both return the updated schedule in the same shape as the list items. Pausing a paused schedule changes nothing.

**schedule\_id** `string` *required*

The schedule ID.

### Errors

| Status | Code | Meaning |
| - | - | - |
| `404` | `schedule_not_found` | No schedule with this ID in your organization. |
| `409` | `schedule_archived` | The schedule was stopped. Create a new one in Coverbase instead. |

## List document insight pending changes

**method** `GET`

`GET /v1/document-insight-pending-changes`

Returns the field changes that document insights propose, newest first. An insight with a review-required update policy holds each change here until a person approves or rejects it in Coverbase. API keys cannot approve or reject changes.

**config\_id** `string`

Only changes from this document insight.

**document\_id** `string`

Only changes from this document.

**status** `string[]`

Any of `pending`, `approved`, `rejected`, `superseded`. Repeat the parameter for more than one.

**limit** `integer` (default: 50)

Page size, from 1 to 200.

**offset** `integer` (default: 0)

Number of changes to skip.

### Response

**items** `object[]`

**pending change**

**id** `string`

Pending change ID.

**config\_id** `string`

The document insight that proposed the change.

**document\_id** `string`

The document the value came from.

**target\_object\_type** `string`

The kind of record the change writes to, for example `vendor`.

**target\_object\_id** `string`

The record the change writes to.

**field\_name** `string | null`

The built-in field the change writes.

**custom\_field\_config\_id** `string | null`

The custom field the change writes.

**current\_value** `any`

What the field holds now.

**proposed\_value** `any`

What the field would become.

**status** `string`

`pending`, `approved`, `rejected`, or `superseded`.

**resolved\_at** `integer | null`

Unix timestamp of the decision.

**created\_at** `integer`

Unix timestamp.

## Get the dark web summary

**method** `GET`

`GET /v1/dark-web/summary`

Returns the dark web monitoring rollup: open exposures by severity and category, recent activity, and how many identifiers and vendors you monitor. Vendor exposures follow the key's vendor read scope.

### Response

**is\_enabled** `boolean`

Whether monitoring is switched on.

**open\_total** `integer`

Open exposures.

**open\_by\_severity** `object`

Open exposures per severity.

**open\_by\_category** `object`

Open exposures per category.

**new\_last\_7\_days** `integer`

Exposures first seen in the last 7 days.

**closed\_total** `integer`

Closed exposures.

**needs\_review** `integer`

Exposures waiting for review.

**with\_legal** `integer`

Exposures sent to Legal.

**monitored\_assets** `integer`

Identifiers on the watchlist.

**monitored\_vendors** `integer`

Vendors in monitoring scope.

**last\_sweep\_at** `integer | null`

Unix timestamp of the last sweep.

## List dark web exposures

**method** `GET`

`GET /v1/dark-web/exposures`

Returns dark web exposures, worst severity first. Each item masks the identifier it matched. To see the full identifier and evidence, open the exposure in Coverbase.

**review\_status** `string[]`

Review statuses to include, for example `new` or `confirmed`.

**severity** `string[]`

Severities to include, for example `critical` or `high`.

**vendor\_id** `string[]`

Only exposures for these vendors.

**search** `string`

Text match on the title and source.

**limit** `integer` (default: 50)

Page size, from 1 to 200.

**offset** `integer` (default: 0)

Number of exposures to skip.

### Response

**items** `object[]`

**exposure**

**id** `string`

Exposure ID.

**subject\_kind** `string`

`organization` or `vendor`.

**vendor\_id** `string | null`

The vendor the exposure concerns.

**asset\_id** `string`

The watchlist identifier that matched.

**masked\_identifier** `string`

The matched identifier, masked.

**source\_name** `string`

Where the exposure was found.

**category** `string`

For example `credential_leak` or `ransomware_victim`.

**severity** `string`

Severity.

**title** `string`

Short description.

**review\_status** `string`

Where the exposure is in review.

**first\_seen\_at** `integer`

Unix timestamp.

**last\_seen\_at** `integer`

Unix timestamp.

## List vendor certificates

**method** `GET`

`GET /v1/vendor-certificates`

Returns the vendor certificates in the Certificate Vault, soonest-expiring first.

**vendor\_id** `string`

Only this vendor's certificates.

**certificate\_type** `string[]`

Certificate types to include.

**validity** `string[]`

Any of `valid`, `expiring`, `expired`.

**search** `string`

Text match on the certificate or vendor name.

**limit** `integer` (default: 50)

Page size, from 1 to 500.

**offset** `integer` (default: 0)

Number of certificates to skip.

### Response

**items** `object[]`

**certificate**

**id** `string`

Certificate ID.

**vendor\_id** `string`

The vendor that holds the certificate.

**certificate\_type** `string`

Certificate type.

**name** `string`

Certificate name.

**issuer** `string | null`

Who issued it.

**valid\_from** `integer | null`

Unix timestamp.

**valid\_to** `integer | null`

Unix timestamp.

**source** `string`

Where Coverbase got the certificate.

**verification\_status** `string`

Whether a person verified it.

## List Inspect applications

**method** `GET`

`GET /v1/inspect-applications`

Returns the applications Inspect monitors, most recently updated first.

**include\_archived** `boolean` (default: false)

Set to `true` to include archived applications.

**limit** `integer` (default: 50)

Page size, from 1 to 500.

**offset** `integer` (default: 0)

Number of applications to skip.

Each item has `id`, `display_name`, `auth_method`, `platform_key`, `vendor_id`, and `is_archived`.

## List inspections

**method** `GET`

`GET /v1/inspections`

Returns Inspect inspections, newest first.

**target\_id** `string`

Only inspections of this application.

**limit** `integer` (default: 20)

Page size, from 1 to 500.

**offset** `integer` (default: 0)

Number of inspections to skip.

Each item has `id`, `target_id`, `app_name`, `purpose`, `status`, `is_archived`, `started_at`, `finished_at`, and `created_at`.

## List document insights

**method** `GET`

`GET /v1/document-insights`

Returns your document insights: the fields Coverbase extracts from documents.

**search** `string`

Text match on the insight name.

**enabled** `boolean`

Only enabled (`true`) or disabled (`false`) insights.

**include\_archived** `boolean` (default: false)

Set to `true` to include archived insights.

**limit** `integer` (default: 100)

Page size, from 1 to 500.

**offset** `integer` (default: 0)

Number of insights to skip.

Each item has `id`, `field_name`, `field_key`, `field_description`, `field_type`, `field_mode`, `enabled`, `is_archived`, `document_types`, and `update_policy`.

## List a document's insight values

**method** `GET`

`GET /v1/document-insight-values`

Returns the insight values Coverbase extracted from one document. The response has `items` and `total`.

**document\_id** `string` *required*

The vendor document ID.

Each item has `id`, `config_id`, `field_name`, `value`, `source_quote`, `source_page_number`, `confidence`, `source_type`, and `answer_accepted_at`.

## Create an Inspect schedule

**method** `POST`

`POST /v1/inspect-schedules`

Returns `201` with the new schedule. A drift schedule repeats every `interval_seconds`; every other purpose runs monthly on `day_of_month`.

**target\_id** `string` *required*

The Inspect application to inspect.

**control\_set\_ids** `string[]` *required*

Control sets each inspection checks, in order.

**day\_of\_month** `integer`

Day of the month to run, for evaluative and exploratory schedules.

**interval\_seconds** `integer`

Seconds between runs, for drift schedules.

**purpose** `string` (default: evaluative)

`evaluative`, `exploratory`, or `drift`.

**browser\_evidence\_allowed** `boolean` (default: true)

Whether inspections may collect browser evidence.

An unknown application returns `422` with `target_not_found`, an archived one `target_archived`, and an invalid cadence or control set `schedule_invalid`.

To change a schedule's cadence or control sets, send `PATCH /v1/inspect-schedules/{schedule_id}` with any of `day_of_month`, `interval_seconds`, and `control_set_ids`. To stop it for good, send `DELETE /v1/inspect-schedules/{schedule_id}`.

## Create and manage document insights

To create an insight, send `POST /v1/document-insights`. It returns `201` with the insight.

**field\_name** `string` *required*

The insight's name, for example "Governing law".

**field\_key** `string`

A stable key. Defaults to `field_name`. A key already in use returns `409` with `field_key_exists`.

**field\_description** `string`

What to extract and how.

**field\_type** `string` (default: string)

`string`, `number`, `date`, or `boolean`.

**field\_mode** `string` (default: extraction)

`extraction` quotes the document; `synthesis` writes text from it.

**document\_types** `string[]`

Document types the insight reads. Empty means all.

**group\_id** `string`

The insight group to file it under.

**update\_policy** `string` (default: auto\_fill)

`auto_fill`, or `review_required` to hold each change for a reviewer.

**reviewer\_user\_id** `string`

The reviewer for `review_required` changes.

To change an insight, send `PATCH /v1/document-insights/{config_id}` with the fields to change. Send `reviewer_user_id: null` to clear the reviewer. `apply_mode` decides what the new definition reaches: `forward_only` (the default) re-runs nothing, `selected` re-runs the documents in `document_ids`, and `all_historical` re-runs every in-scope document an older revision filled. A re-run starts in the background and its id comes back as `backfill_id`; poll `GET /v1/document-insight-backfills/{backfill_id}`. When a running backfill or a daily ceiling blocks the re-run, nothing is saved and the response is `409`, `422`, or `429` with `backfill_refused`. Making a synthesis insight anything but text returns `422` with `synthesis_needs_text`.

To edit many insights at once, send `POST /v1/document-insights/bulk-update` with `config_ids` (up to 200) and any of `enabled`, `group_id`, `clear_group`, `add_document_types`, and `remove_document_types`. Document types are added and removed, never replaced. To archive many at once, send `POST /v1/document-insights/bulk-archive` with `config_ids`; API keys cannot do this. Both return `updated_count` and the changed insights in `items`.

To retire an insight and keep its values, send `POST /v1/document-insights/{config_id}/archive`. To bring it back, send `POST /v1/document-insights/{config_id}/restore`.

### Targets

A target links an insight to a built-in contract or document field it fills. To list them, send `GET /v1/document-insights/{config_id}/targets`. To add one, send `POST /v1/document-insights/{config_id}/targets` with `object_type` (`contract` or `vendor_document`), `field_name`, and optionally `conflict_policy` (`fill_if_empty`, `latest_document_wins`, `never_overwrite`), `min_confidence` (`low`, `medium`, `high`), `require_grounded`, and `enabled`. A pairing no parser covers returns `422` with `target_not_supported`; a field the insight already fills returns `409` with `target_exists`.

To change a target, send `PATCH /v1/document-insight-targets/{target_id}`. To stop filling the field, send `DELETE /v1/document-insight-targets/{target_id}`. Values already written stay.

### Groups

To list groups, send `GET /v1/document-insight-groups`. To create one, send `POST /v1/document-insight-groups` with `name` and optionally `description`, `document_types`, `sort_order`, and `enabled`. To change one, send `PATCH /v1/document-insight-groups/{group_id}`; changing `document_types` rescopes every insight that inherits from the group. To delete one, send `DELETE /v1/document-insight-groups/{group_id}`. Its insights stay, outside any group.

### Coverage

`GET /v1/document-insight-stats` returns one row per insight with how many eligible documents it applies to, how many hold a value, and its fill rate. Pass `config_id` one or more times to read only those insights.

## Manage dark web monitoring

To read the policy, send `GET /v1/dark-web/config`. To change it, send `PATCH /v1/dark-web/config` with any of `is_enabled`, `monitor_organization`, `vendor_scope` (`radar_monitored` or `all`), `enabled_sources`, `lookalikes_for_vendors`, `confidence_threshold` (0 to 1), and `business_hours`. Coverbase re-derives the watchlist right away, and switching monitoring on creates the dark web roles.

### Review an exposure

To record a triage decision, send `PATCH /v1/dark-web/exposures/{exposure_id}/review`. Only the fields you send change.

**review\_status** `string`

The new review status. Coverbase records every step in between.

**review\_note** `string`

A note on the decision. Send `null` to clear it.

**false\_positive\_reason** `string`

Required with `false_positive`.

**assigned\_user\_id** `string`

Assign the exposure to this member. They are notified.

**clear\_assignee** `boolean` (default: false)

Remove the current assignee.

Moving to `new`, `confirmed`, or `with_legal` runs your alert rules. Errors: `404` `exposure_not_found`, `422` `assignee_not_member`, `422` `review_not_allowed`.

### Watchlist

To list watched identifiers, send `GET /v1/dark-web/watchlist`. Values are masked. To add one, send `POST /v1/dark-web/watchlist` with `subject_kind` (`organization` or `vendor`), `asset_type`, `value`, and `vendor_id` for a vendor identifier. Optional fields: `label`, `role` (domains), `program_vendor_id`, `card_kind`, `card_network` (BINs), and `linked_asset_id` (mailboxes). Adding an identifier already there re-enables it.

To turn one on or off or change its details, send `PATCH /v1/dark-web/watchlist/{asset_id}`. To stop watching it, send `DELETE /v1/dark-web/watchlist/{asset_id}`; a derived identifier is switched off instead of removed.

### Playbooks

To list every response checklist, send `GET /v1/dark-web/playbooks`. To replace one with your own steps, send `PUT /v1/dark-web/playbooks/{key}` with `steps`, a list of `{ "id": optional, "label": required }`. To go back to Coverbase's default, send `DELETE /v1/dark-web/playbooks/{key}`.

## Manage certificates and prequalification

To record a certificate by hand, send `POST /v1/vendor-certificates` with `vendor_id`, `certificate_type`, `name`, and optionally `issuer`, `scope`, `result`, `coverages`, `valid_from`, `valid_to`, and `vendor_document_id`. Coverbase re-checks the vendor's prequalification.

To record a person's check, send `PATCH /v1/vendor-certificates/{certificate_id}/verification` with `verification_status` (`unverified`, `verified`, `discrepancy`) and `verification_note`. To archive a certificate, send `DELETE /v1/vendor-certificates/{certificate_id}`.

To ask a vendor for a certificate, send `POST /v1/vendor-certificate-requests` with `vendor_id`, `certificate_type`, `message`, and `due_at`. The response gives the unsent supplier portal's `portal_id`.

To ask for renewals in bulk, send `POST /v1/certificate-renewal-jobs` with `certificate_ids`, `message`, and `due_at`. It returns `202` with the job. To follow it, poll `GET /v1/certificate-renewal-jobs/{job_id}` until `status` is final; the counts show how many requests were sent, skipped, or failed.

To pull certificates from a connected network now, send `POST /v1/certificate-networks/{network}/sync` with `isnetworld`, `avetta`, or `ecovadis`. It returns `202`.

### Rule sets

A rule set lists the certificates vendors must hold. To list them, send `GET /v1/prequalification-rule-sets`. To create or replace one, send `POST /v1/prequalification-rule-sets` or `PUT /v1/prequalification-rule-sets/{rule_set_id}` with `name`, `description`, `applies_to`, `rules`, `expiry_reminder_days`, and `blocks_on_failure`. Coverbase re-checks every governed vendor in the background. To archive one, send `DELETE /v1/prequalification-rule-sets/{rule_set_id}`.

To see where a vendor stands, send `GET /v1/vendors/{vendor_id}/prequalification`. To re-check it now, send `POST /v1/vendors/{vendor_id}/prequalification/refresh`.

## Get a vendor's security benchmark

**method** `GET`

`GET /v1/vendors/{vendor_id}/security-benchmark`

Returns where the vendor's outside-in security score sits among your other rated vendors: `score`, `rated_vendors`, `percentile` (null until enough vendors are rated), and `grade_counts`.

## Query the Certificate Vault

**method** `POST`

`POST /v1/vendor-certificates/query`

Returns certificates that match a unified filter, in the same shape as the list endpoint.

**vendor\_id** `string`

Only this vendor's certificates.

**search** `string`

Text match on the certificate or vendor name.

**filter** `object`

A unified filter rule group, the same DSL the other `/query` endpoints take.

**sort\_by** `string`

One of `vendor_name`, `name`, `certificate_type`, `source`, `valid_to`, `created_at`.

**sort\_desc** `boolean` (default: false)

Sort descending.

**limit** `integer` (default: 50)

Page size, from 1 to 500.

**offset** `integer` (default: 0)

Number of certificates to skip.

To see which certificate networks you connected, send `GET /v1/certificate-networks`. Each item has `network`, `display_name`, `is_connected`, `certificate_count`, and `last_synced_at`. Credentials are never returned.

## Correct a vendor's external security scan

These endpoints change what the outside-in scan sees. The scan target belongs to the company, so every org linked to it sees the correction. Each write that changes the scan starts a rescan; `rescan_started` false means the rescan is queued, not dropped.

* To point the scan at the right domain, send `POST /v1/vendors/{vendor_id}/external-security/rescan` with `domain`. The response gives the host it reduced to.
* To record whether an attributed asset is the vendor's, send `POST /v1/vendors/{vendor_id}/external-security/estate-reviews` with `kind` (`domain` or `host`), `identifier`, `review` (`unreviewed`, `confirmed`, `disputed`), and an optional `note`. Only a change into or out of `disputed` starts a rescan.
* To add hosts or addresses the scan missed, send `POST /v1/vendors/{vendor_id}/external-security/estate-assets` with `identifiers` and an optional `note`. The response lists `added`, `already_present`, and `rejected`.
* To see the companies the rating is compared against, send `GET /v1/vendors/{vendor_id}/external-security/peers`. To queue the work a stale comparison needs, send `POST /v1/vendors/{vendor_id}/external-security/peers/refresh`. Set `force` to re-choose the peers.

Errors use the codes `not_found`, `forbidden`, and `invalid`.

## List continuous monitoring findings

To list findings about your vendors, send `GET /v1/vendor-scan-results` with optional `vendor_id`, `risk_category`, `severity_low`, `severity_high`, `limit`, and `offset`. To get one, send `GET /v1/vendor-scan-results/{scan_result_id}`. Each item has `title`, `summary`, `risk_category`, `severity`, `urls`, and `published_at`.

## Review an extracted insight value

To accept an extracted value as the answer, send `POST /v1/document-insight-values/{data_id}/accept` with the value you saw in `value_string`, `value_number`, `value_date`, or `value_boolean`. A value that changed since returns `409` with `value_changed`. Accepting does not claim the quote was verified.

To mark a value correct or incorrect, send `POST /v1/document-insight-values/{data_id}/verdict` with `verdict` (`correct`, `incorrect`, or null to clear).

## Teach a document insight with examples

A worked example shows an insight an excerpt and the answer it should give. An enabled example is part of what extraction is asked, so each change starts a new revision of the insight.

* To list examples, send `GET /v1/document-insights/{config_id}/examples`.
* To add one, send `POST /v1/document-insights/{config_id}/examples` with `document_excerpt`, `expected_value` (the answer in the insight's type, or null for "not in the document"), and optionally `explanation`, `document_id`, and `enabled`. An answer that does not fit the insight's type returns `422` with `invalid_expected_value`.
* To change one, send `PATCH /v1/document-insight-examples/{example_id}`. Only the fields you send change.
* To delete one, send `DELETE /v1/document-insight-examples/{example_id}`.
* To build an example from an extracted value, send `POST /v1/document-insight-values/{data_id}/to-example` with an optional `explanation`. A value that cites no document text returns `422` with `no_cited_text`.

## Re-run insights over existing documents

A backfill re-extracts insights in the background and costs model calls. Manual values are never overwritten.

To see what a backfill would do, send `POST /v1/document-insight-backfills/preview`. It runs nothing.

**mode** `string` (default: never\_attempted)

`never_attempted`, `missing_only`, `outdated_revision`, or `all`.

**insight\_config\_ids** `string[]`

Insights to re-run. Empty means every enabled insight.

**document\_type\_slugs** `string[]`

Only these document types.

**vendor\_ids** `string[]`

Only these vendors' documents.

**document\_ids** `string[]`

Only these documents.

**include\_manually\_cleared** `boolean` (default: false)

Re-fill values a person emptied on purpose.

The preview returns `document_count`, `insight_count`, `estimated_model_calls`, `manually_cleared_count`, and `blocked_reason` when it could not start now.

To start one, send the same body to `POST /v1/document-insight-backfills`. It returns `202` with the backfill. Poll `GET /v1/document-insight-backfills/{backfill_id}` until `status` is `completed`, `failed`, or `cancelled`. A run over the per-run or per-day ceilings, or with nothing to do, returns `422`, `409`, or `429` with `backfill_refused`. To stop dispatching more documents, send `POST /v1/document-insight-backfills/{backfill_id}/cancel`. Work already started finishes.

## Escalate an exposure, sync the watchlist, and set retention

* To open a finding from an exposure, send `POST /v1/dark-web/exposures/{exposure_id}/escalate` with optional `title` and `assigned_to_id`. A second call returns the same `finding_id`.
* To re-derive the watchlist from your organization and vendor records now, send `POST /v1/dark-web/watchlist/sync`. The response counts identifiers `created`, `kept`, and `archived`.
* To read how long each class of dark web data is kept, send `GET /v1/dark-web/retention`. To change it, send `PUT /v1/dark-web/retention` with `exposures_years`, `evidence_years`, `audit_years`, and `sweep_history_years`. A shorter period purges older data at the next nightly run.

## Work with your organization's own documents

Org documents are files your organization owns, such as policies, questionnaire and report templates, and exports.

* To list them, send `GET /v1/org-documents` with optional `document_type`, `search`, `limit`, and `offset`.
* To download one, send `GET /v1/org-documents/{document_id}/download`. The response gives a presigned `url` that is valid for `expires_in` seconds. Follow it with a plain `GET` and no auth header.
* To rename, retype, archive, or restore one, send `PATCH /v1/org-documents/{document_id}` with any of `name`, `document_type`, and `is_archived`.
* To upload one, send `POST /v1/org-documents` as `multipart/form-data` with `file` and optional `document_type` and `name`. It returns `201` with the document. An `assessment_report_template` must be a valid `.docx`: another extension returns `400` with `template_must_be_docx`, and a file that does not open as Word returns `400` with `invalid_template`.

## Correct or remove extracted values

* To replace an extracted value with the right one, send `POST /v1/document-insight-values/{data_id}/correct` with one of `value_string`, `value_number`, `value_date`, or `value_boolean`. The correction becomes a manual value that no re-extraction overwrites, and Coverbase writes it to linked fields. A value that does not fit the insight's type returns `422` with `invalid_value`.
* To delete a value, send `DELETE /v1/document-insight-values/{data_id}`.
* To judge many values at once, send `POST /v1/document-insight-values/bulk-verdict` with `ids` and `verdict` (`correct`, `incorrect`, or null). The response gives `updated_count` and `found_count`; a value that already holds the verdict is skipped.

## Fill a custom field from a document insight

Promoting an insight links it to a custom field on vendors, services, assessments, or contracts, so each extracted value also fills that field.

* To see which custom fields an insight could fill, send `GET /v1/document-insights/{config_id}/promotion-options`. `compatible_field_type` names the custom field type the insight can fill, or is null when its type cannot fill one yet. Each item gives `custom_field_id`, `field_name`, `field_type`, `applied_to`, and `is_linked`.
* To link it, send `POST /v1/document-insights/{config_id}/promote` with either `custom_field_id` (an existing field) or `new_field_name` and `applied_to` (`vendor`, `service`, `assessment`, or `contract`) to create one. Optional fields are `require_grounded` (default `true`), `min_confidence` (`high`, `medium`, or `low`; default `medium`), `conflict_policy` (`never_overwrite`, `fill_if_empty`, or `latest_document_wins`; default `fill_if_empty`), and `backfill` (default `true`, which fills the field from existing documents in the background). The response gives `custom_field_id`, `created_custom_field`, and `backfill_queued`. An archived insight returns `409` with `document_insight_archived`, a field that already has another autofill source returns `409` with `custom_field_has_autofill_source`, and a type or target mismatch returns `422` with `promotion_invalid`.
* To stop filling a field, send `DELETE /v1/document-insights/{config_id}/custom-fields/{custom_field_id}`. It returns `204`. Values already written stay. A field the insight does not fill returns `409` with `custom_field_not_linked`.

## Train a decision model

A decision model is the model document insight extraction uses for your organization. You can start one from a base model, train it on your verified values, and switch extraction to it once it scores at least as well as the standard model. Responses never include storage locations or job identifiers.

* To list models, send `GET /v1/document-insight-models`. The response also gives `base_model_ids` you can start from, `active_model_id`, and `training_configured`.
* To start one, send `POST /v1/document-insight-models` with `name` and `base_model_id`. An unlisted base model returns `422` with `base_model_not_allowed`.
* To collect verified values into its training set, send `POST /v1/document-insight-models/{model_id}/dataset`. `dataset_stats` gives the counts.
* To compare it with the standard model, send `POST /v1/document-insight-models/{model_id}/evaluate` with an optional `max_documents` (1 to 100, default 25). It returns `202` and costs model calls. Poll the list until `eval_result.status` is no longer `running`.
* To start fine-tuning, send `POST /v1/document-insight-models/{model_id}/training`. Training runs for hours. To record its progress, send `POST /v1/document-insight-models/{model_id}/training/sync`.
* To switch extraction to it, send `POST /v1/document-insight-models/{model_id}/activate`. A trained model is held back until its accuracy check passes; `activation_blocked_reason` says why.
* To retire it, send `POST /v1/document-insight-models/{model_id}/retire`. Retiring the active model returns extraction to the standard model. API keys cannot retire.

A step the model's state refuses, such as evaluating a retired model or training without a dataset, returns `409` with `decision_model_conflict`.

## Add an Inspect application

**method** `POST`

`POST /v1/inspect-applications`

Adds an application for Inspect to sign in to and check, and returns it with `201`. When the application's login domain matches exactly one of your vendors, Coverbase links that vendor.

**display\_name** `string` *required*

The name you see for the application.

**auth\_method** `string` *required*

How Inspect signs in: `password_url`, `okta_app`, `entra_app`, or `oauth_google`.

**login\_url** `string`

The sign-in page, as an absolute `http` or `https` URL. Required for `password_url` and `oauth_google`. For `okta_app` and `entra_app`, Coverbase uses the URL the identity provider reports when you leave it out.

**okta\_application\_id** `string`

The Okta application ID. Required for `okta_app`, and Okta must be connected.

**entra\_application\_id** `string`

The Entra application ID. Required for `entra_app`, and Entra must be connected.

**platform\_key** `string`

The SaaS platform the application runs on, from `GET /v1/inspect-platforms`.

**api\_authority** `string`

The HTTPS origin of the application's API, for example `https://api.example.com`.

To add up to 200 applications in one request, send `POST /v1/inspect-applications/bulk` with `applications`, a list of the same objects. Coverbase validates every entry before it creates any, so one invalid entry refuses the whole batch. The response has `items` in request order.

### Response

**id** `string`

Application ID.

**display\_name** `string`

The application's name.

**auth\_method** `string`

How Inspect signs in.

**login\_url** `string | null`

The sign-in page.

**api\_authority** `string | null`

The API origin.

**okta\_application\_id** `string | null`

The linked Okta application.

**entra\_application\_id** `string | null`

The linked Entra application.

**platform\_key** `string | null`

The SaaS platform.

**is\_archived** `boolean`

Whether the application is archived.

**has\_verification\_factor** `boolean`

Whether a one-time code or passkey factor is enrolled.

**vendor\_match\_status** `string`

`linked`, `suggested`, `ambiguous`, or `unresolved`.

**vendor\_id** `string | null`

The linked vendor.

**suggested\_vendor\_id** `string | null`

The one vendor that matches the login domain, when the application has no vendor yet.

**candidate\_vendor\_ids** `string[]`

Vendors that match when the match is ambiguous.

### Errors

| Status | Code | Meaning |
| - | - | - |
| `404` | `okta_application_not_found` | No synced Okta application with this ID. |
| `404` | `entra_application_not_found` | No synced Entra application with this ID. |
| `409` | `okta_not_connected` | Okta is not connected for your organization. |
| `409` | `entra_not_connected` | Entra is not connected for your organization. |
| `422` | `login_url_required` | The sign-in method needs `login_url`. |
| `422` | `login_url_invalid` | `login_url` is not an absolute `http` or `https` URL with a hostname. |
| `422` | `login_url_unresolved` | The identity provider reports no login URL. Send `login_url` or sync the provider again. |
| `422` | `okta_application_required` | `okta_app` needs `okta_application_id`. |
| `422` | `entra_application_required` | `entra_app` needs `entra_application_id`. |
| `422` | `platform_invalid` | The platform key is unknown, or the API origin is not one the platform declares. |

## Get or change an Inspect application

To read one application, send `GET /v1/inspect-applications/{application_id}`. It returns the same shape as the create response. An unknown ID returns `404` with `application_not_found`.

To rename an application or change its login URL, send `PATCH /v1/inspect-applications/{application_id}` with `display_name`, `login_url`, or both. Omitted fields keep their value. To make an Okta or Entra application use the URL its identity provider reports, send `login_url: null`. A `password_url` or `oauth_google` application keeps its URL and returns `422` with `login_url_required`. A blank name returns `422` with `display_name_blank`.

To link an application to one of your vendors, send `PUT /v1/inspect-applications/{application_id}/vendor` with `vendor_id`. An unknown or archived vendor returns `404` with `vendor_not_found`.

To set the platform, send `PUT /v1/inspect-applications/{application_id}/platform` with `platform_key` (or null to clear it) and an optional `api_authority`. When you leave out `api_authority`, the current one stays.

To link several applications to their suggested vendors, send `POST /v1/inspect-applications/link-suggested-vendors` with up to 200 `application_ids`. An application that already has a vendor, or whose match is ambiguous, stays as it is. When an ID is unknown, nothing changes and the endpoint returns `404` with `application_not_found`.

All of these need the `integration:update:org` permission, except the read, which needs `integration:read:org`.

## Archive or delete an Inspect application

To stop Inspect checking an application and keep its history, send `POST /v1/inspect-applications/{application_id}/archive`. To restore it, send `POST /v1/inspect-applications/{application_id}/unarchive`. To archive or restore up to 200 at once, send `POST /v1/inspect-applications/bulk-archive` with `application_ids` and `is_archived`.

To delete an application for good, send `DELETE /v1/inspect-applications/{application_id}`. Coverbase removes its saved sign-in sessions and stored credentials, then returns `204`. You cannot undo a delete.

API keys cannot archive, restore, or delete applications. A signed-in user must do it.

### Errors

| Status | Code | Meaning |
| - | - | - |
| `403` | `api_key_not_allowed` | An API key called the endpoint. |
| `404` | `application_not_found` | No application with this ID in your organization. |
| `409` | `identity_reconciliation_busy` | Coverbase is reconciling identities for your organization. Try again shortly. |
| `500` | `sessions_not_revoked` | A saved sign-in session could not be removed, so nothing was deleted. |
| `500` | `credentials_not_deleted` | A stored credential could not be removed, so nothing was deleted. |

## Read setup options and platforms

To list what you can pick when you start an inspection, send `GET /v1/inspect-setup-options`. The response has `applications` (each with `id` and `display_name`) and `control_sets` (each with `id`, `name`, and `control_count`). Only internal control sets with at least one active control appear.

To list the platform keys you can assign to an application, send `GET /v1/inspect-platforms`. The response has `platform_keys`.

Both need the `integration:read:org` permission.

## Read and change an application's config

**method** `GET`

`GET /v1/inspect-applications/{application_id}/config`

Returns how Inspect signs in to an application and calls its API. Each credential field says whether a value is stored. The API never returns a stored credential or where it is kept.

### Response

**application\_id** `string`

Application ID.

**display\_name** `string`

The application's name.

**auth\_method** `string | null`

How Inspect signs in.

**credentials\_configured** `boolean`

Whether every required credential is stored, or a ready single sign-on session covers it.

**credential\_fields** `object[]`

Each with `key`, `label`, `input_kind`, `usage` (`sign_in`, `sso_identity`, or `api`), `required`, and `configured`.

**api\_authentication\_parameters** `object[]`

Each with `key`, `label`, `description`, and the stored `value`.

**request\_parameters** `object[]`

API request parameters the application's plans need. Each with `key`, `name`, `location` (`path` or `query`), `value_type`, `description`, `allowed_values`, and the stored `value`.

**api\_authority** `string | null`

The API origin.

**method** `PATCH`

`PATCH /v1/inspect-applications/{application_id}/config`

To set an application's API settings, send any of `api_authentication_parameters` and `request_parameters` (objects keyed by the `key` the read returns) and `api_authority`. Coverbase validates every value before it saves any, and returns the updated config. You set sign-in and API credentials in Coverbase, not through the API, so a `credentials` field returns `422`.

The read needs `integration:read:org` and the update needs `integration:update:org`.

### Errors

| Status | Code | Meaning |
| - | - | - |
| `404` | `application_not_found` | No application with this ID in your organization. |
| `422` | `request_parameter_unknown` | A request parameter key the application's plans do not use. |
| `422` | `request_parameter_invalid` | A request parameter value that does not fit its type or allowed values. |
| `422` | `authentication_parameter_unknown` | An API authentication parameter key the application does not use. |
| `422` | `authentication_parameter_invalid` | An API authentication parameter value that is not valid. |
| `422` | `api_authority_undeclared` | An API origin the application's platform does not declare. |

## Prepare Inspect plans

A plan says which evidence Inspect collects for one control on one platform, and how. Inspect can start an inspection only when every control in the chosen set has a ready plan.

**method** `GET`

`GET /v1/inspect-plans/readiness`

Reports whether a control set is ready for an application. Needs `integration:read:org`.

**control\_set\_id** `string` *required*

The internal control set.

**application\_id** `string` *required*

The Inspect application. It must have a platform.

**browser\_evidence\_allowed** `boolean` (default: true)

Set to `false` to count only API evidence.

The response gives the set's readiness and each control's plan or preparation.

**method** `POST`

`POST /v1/inspect-plans/ensure`

To prepare the missing plans, send `control_set_id`, `application_id`, and an optional `browser_evidence_allowed`. Preparation runs in the background, and the response is the readiness after Coverbase queued it. Poll `GET /v1/inspect-plans/readiness` until the set is ready. Needs `integration:run:org`.

### Errors

| Status | Code | Meaning |
| - | - | - |
| `404` | `target_not_found` | No application with this ID in your organization. |
| `422` | `target_not_found` | The application is archived. |
| `422` | `target_platform_missing` | The application has no platform. Set one with `PUT /v1/inspect-applications/{application_id}/platform`. |
| `422` | `plan_selection_invalid` | The control set is not an internal set in your organization, or has no active controls. |
| `409` | `plan_version_conflict` | Another request changed the plans at the same time. Try again. |

## Read and edit an Inspect plan

To read a plan, send `GET /v1/inspect-plans/{plan_id}`. The response has `id`, `source_control_id`, `platform_key`, `version`, `scope` (`public` or `organization`), `is_latest_version`, `superseded_reason`, `outdated`, `plan_content_hash`, the full `plan`, and `created_at`. `outdated` is `true` when newer documentation or a newer planner would build a different plan.

To list a plan's published versions without their bodies, send `GET /v1/inspect-plans/{plan_id}/versions`. Each item has `id`, `version`, `plan_content_hash`, `is_latest_version`, `superseded_reason`, `published_by_user_id`, `derived_from_plan_id`, and `created_at`.

To edit a plan, send the whole edited `plan` with the `plan_content_hash` you read:

* To check an edit without saving it, send `POST /v1/inspect-plans/{plan_id}/revisions/validate`. The response gives the `plan_content_hash` that publishing would store.
* To publish it as the next version, send `POST /v1/inspect-plans/{plan_id}/revisions`. It returns `201` with the new version.

To customize a public plan, also send `control_id`, one of your own controls the plan covers. You can change wording and route hints. You cannot change what evidence the plan collects.

Reads need `integration:read:org`. Edits need `integration:update:org`.

### Errors

| Status | Code | Meaning |
| - | - | - |
| `404` | `plan_not_found` | No plan with this ID that your organization can see. |
| `409` | `plan_version_conflict` | Someone published a version since you read `plan_content_hash`. Read the plan again. |
| `409` | `plan_already_customized` | Your organization already customized this public plan. Edit your version instead. |
| `422` | `plan_contract_changed` | The edit changes the evidence the plan collects. |
| `422` | `plan_field_not_editable` | The edit changes a field you cannot edit. |
| `422` | `plan_route_hint_invalid` | A route hint is not valid for the platform. |
| `422` | `plan_text_required` | A text field is empty. |
| `422` | `plan_text_too_long` | A text field is too long. |
| `422` | `plan_text_unsupported` | A text field holds characters Inspect does not accept. |
| `422` | `plan_selection_invalid` | `control_id` does not match the plan. |
| `503` | `plan_storage_unavailable` | Plan sources cannot be loaded right now, so the edit cannot be checked. |

## Regenerate an Inspect plan

When a plan is `outdated`, you choose when to replace it. To retire your organization's plan and prepare a fresh one, send `POST /v1/inspect-plans/{plan_id}/regenerate`. The retired version stays readable, and inspections that used it keep it. The response has `superseded_plan_id` and the `preparation`, which is null when a current public plan already covers the control.

To redesign how Inspect checks one requirement after a run failed it, send `POST /v1/inspect-plans/{plan_id}/requirements/{requirement_key}/regenerate` with the `run_id`. The plan stays live until the new version publishes. The response has the `preparation`.

Both need `integration:update:org`.

### Errors

| Status | Code | Meaning |
| - | - | - |
| `404` | `plan_not_found` | No plan with this ID in your organization. |
| `409` | `plan_version_conflict` | The plan changed at the same time. Try again. |
| `422` | `plan_regeneration_refused` | The control is archived, or its platform has no documentation, so nothing would replace the plan. |
| `422` | `requirement_regeneration_refused` | The run did not fail this requirement, or the requirement cannot be redesigned. |
| `503` | `plan_preparation_unavailable` | Plan preparation cannot run right now. Nothing changed. |

## Start an inspection

**method** `POST`

`POST /v1/inspections`

Starts an inspection of one application against one or more control sets, and returns it with `201`. The inspection runs in the background. To follow it, poll `GET /v1/inspections/{inspection_id}`. Every control needs a ready plan first, so check `GET /v1/inspect-plans/readiness` and prepare missing plans with `POST /v1/inspect-plans/ensure`.

**application\_id** `string` *required*

The Inspect application.

**control\_set\_ids** `string[]` *required*

The internal control sets to check.

**purpose** `string` (default: evaluative)

`evaluative` scores each control, `exploratory` collects evidence without a score, and `drift` compares against an earlier inspection.

**reference\_inspection\_id** `string`

For `drift` only: a finished inspection of the same application that ran every control set you send.

**vendor\_id** `string`

The vendor to attribute results to. It defaults to the application's vendor and must match it when the application has one.

**schedule\_id** `string`

Links the inspection to a schedule. The schedule must be active and match the application, vendor, control sets, purpose, and `browser_evidence_allowed`.

**browser\_evidence\_allowed** `boolean` (default: true)

Set to `false` to collect only API evidence.

Needs `integration:run:org`.

### Response

**id** `string`

Inspection ID.

**application\_id** `string | null`

The application.

**app\_name** `string`

The application's name when the inspection started.

**vendor\_id** `string | null`

The vendor.

**control\_set\_ids** `string[]`

The control sets checked.

**purpose** `string`

`evaluative`, `exploratory`, or `drift`.

**status** `string`

The inspection's status.

**browser\_evidence\_allowed** `boolean`

Whether browser evidence is collected.

**reference\_inspection\_id** `string | null`

The inspection a drift run compares against.

**schedule\_id** `string | null`

The linked schedule.

**is\_archived** `boolean`

Whether the inspection is archived.

**created\_at** `integer`

Unix timestamp.

**started\_at** `integer | null`

Unix timestamp.

**finished\_at** `integer | null`

Unix timestamp.

**runs** `object[]`

One per control: `id`, `status`, `control_id`, `control_set_id`, `retry_of_run_id`, `started_at`, and `finished_at`.

### Errors

| Status | Code | Meaning |
| - | - | - |
| `400` | `reference_inspection_required` | A `drift` inspection needs `reference_inspection_id`. |
| `400` | `reference_inspection_not_allowed` | Only a `drift` inspection names a reference. |
| `400` | `reference_inspection_incompatible` | The reference inspection checked another application. |
| `400` | `reference_inspection_unusable` | The reference inspection has not finished, observed no evidence, or is a probe sample. |
| `400` | `reference_inspection_controls_missing` | The reference inspection did not run every control set you send. |
| `400` | `schedule_incompatible` | The schedule is stopped or does not match the request. |
| `404` | `target_not_found` | No application with this ID in your organization. |
| `409` | `target_archived` | The application is archived. |
| `409` | `plans_not_ready` | A control has no ready plan. `readiness` in the error says which. |
| `409` | `controls_not_scoreable` | A control set has no control that can be scored. |
| `409` | `authentication_in_progress` | Inspect is refreshing the application's sign-in. Try again shortly. |
| `422` | `vendor_mismatch` | `vendor_id` does not match the application's vendor. |
| `422` | `vendor_unavailable` | The vendor is archived or not found. |
| `422` | `plan_selection_invalid` | A control set is not an internal set in your organization. |

## Find inspections

To read one inspection, send `GET /v1/inspections/{inspection_id}`. It returns the same shape as the create response. An unknown ID returns `404` with `inspection_not_found`.

To filter inspections, send `POST /v1/inspections/query` with an optional `filter` in the [unified filter language](/conventions.md), `sort`, `exclude_probes`, `limit` (1 to 500, default 50), and `offset`. The response has `items` in the shape above, `total`, `limit`, and `offset`.

Both need `integration:read:org`.

## Archive, cancel, or retry inspections

* To archive or restore up to 500 inspections, send `POST /v1/inspections/bulk-archive` with `inspection_ids` and `is_archived` (default `true`). API keys cannot archive or restore inspections, and the call needs `integration:update:org` and `integration:archive:org`.
* To cancel every unfinished control of up to 500 inspections, send `POST /v1/inspections/bulk-cancel` with `inspection_ids`. `affected_ids` lists the inspections that had a control to cancel.
* To cancel some controls of one inspection, send `POST /v1/inspections/{inspection_id}/runs/bulk-cancel` with `run_ids`.
* To run finished controls again, send `POST /v1/inspections/{inspection_id}/runs/bulk-retry` with `run_ids`. Set `use_current_control` to `true` to run each control's current version. When that version has no ready plan, nothing restarts, Coverbase starts preparing the plan, and the call returns `409` with `plans_not_ready`.

Cancel and retry need `integration:run:org`. Each returns `affected_ids`.

### Errors

| Status | Code | Meaning |
| - | - | - |
| `403` | `api_key_not_allowed` | An API key tried to archive or restore inspections. |
| `404` | `inspection_not_found` | An inspection or control run is not in your organization. |
| `409` | `run_not_retryable` | A control run has not finished, so it cannot run again. |
| `409` | `inspection_has_no_application` | The inspection's application was deleted, so it cannot run against the current control. |
| `409` | `plans_not_ready` | The current control has no ready plan yet. Retry after it is ready. |

## Read the Inspect overview

To read your posture score across each application's latest scored inspection, send `GET /v1/inspect-posture`. The response has `percent`, which is null until an application has a scored inspection, and `app_count`.

To read the overview, send `GET /v1/inspect-summary` with an optional `days` (1 to 365, default 30). The response counts issues (`issues_open`, `issues_resolved`, `issues_dismissed`, `issues_total`, and `issues_by_severity`), findings (`findings_new`, `findings_overdue`, `findings_total`), applications (`applications_connected`, `applications_inspected`, `applications_never_inspected`, `applications_with_connection_issues`), and runs (`runs_completed`, `runs_partial`, `runs_failed`, `runs_total`). `top_vendors` and `top_applications` rank by issue count, each with `id`, `name`, and `issue_count`.

Both need `integration:read:org`.

## Work with the identity directory

The identity directory lists the people and services Inspect found in Okta, Entra, and inspected applications, with the accounts each holds.

* To count identities by the views the dashboard offers, send `GET /v1/inspect-identities/summary`. The response has `identities`, `with_accounts`, `guests`, `admin_observed`, `observed`, `needs_attribution`, `observations_total`, and `observations_attributed`.
* To filter identities, send `POST /v1/inspect-identities/query` with an optional `filter`, `sort`, `search`, `limit` (1 to 500, default 50), and `offset`. Each item has `id`, `display_name`, `primary_email`, `association`, `account_count`, `admin_account_count`, `needs_review_count`, and `latest_observed_at`.
* To assign accounts Inspect observed to an identity, send `PUT /v1/inspect-accounts/owner` with `account_ids` and `identity_id`. To hand the accounts back to automatic matching, send `identity_id: null`. Only accounts known from inspections can be assigned.
* To move every observed account of some identities to another identity, send `POST /v1/inspect-identities/merge` with `identity_ids` and `into_identity_id`. You cannot merge away an identity from Okta or Entra.
* To set which SaaS platform an Okta or Entra application is, send `PUT /v1/inspect-idp-applications/{application_id}/platform` with `platform_key`, or null to clear it.
* To read one identity, send `GET /v1/inspect-identities/{identity_id}`. It takes `limit` (1 to 100, default 25) and `offset` for its accounts. The response has the identity's emails, directory records (`principals`), a page of `accounts` with the properties read from each, its `detections`, and `account_count`.
* To read what an identity did in Okta or Entra, send `GET /v1/inspect-identities/{identity_id}/events` with `limit` and `offset`. The response has `sources`, the newest `events` first, and `total_count`.
* To see why an account belongs to an identity, send `GET /v1/inspect-identities/{identity_id}/accounts/{account_id}/evidence` with `limit` (1 to 100, default 5), `offset`, and `kind` (`all`, `events`, or `observations`). The response has `items`, each an observation with the application, run and time it came from.
* To list the applications that hold accounts, send `GET /v1/inspect-account-applications` with an optional `search`, `ids`, and `limit` (up to 100).
* To list application credentials, such as API keys and service tokens Inspect found, send `GET /v1/inspect-credentials`. Filter with `application_id` (repeatable) and `classification` (`ownerless_credential`, `unused_credential`, or `expired_credential`). The response is metadata only: type, owner, expiry, last use, and detections. It never holds a secret value.
* To rebuild the whole inventory, send `POST /v1/inspect-identities/reconcile`. It returns `202` with `request_id` and `queued`. Only an organization admin can start a rebuild, so API keys cannot. Poll `GET /v1/inspect-identities/reconcile/{request_id}`, which returns `status`: `queued`, `running`, `succeeded`, or `failed`.

An owner change or merge returns `request_id` and `queued`. Coverbase then rebuilds the identity inventory in the background, so counts follow the decision within a few minutes. Reads need `integration:read:org` and changes need `integration:update:org`. A full rebuild needs `integration:run:org`.

### Errors

| Status | Code | Meaning |
| - | - | - |
| `400` | `sort_invalid` | A sort field the directory cannot sort by. |
| `404` | `identity_not_found` | No identity with this ID in your organization. |
| `404` | `idp_application_not_found` | No Okta or Entra application with this ID. |
| `404` | `account_not_found` | The account does not belong to this identity. |
| `403` | `admin_required` | Only an organization admin can rebuild the inventory. API keys cannot. |
| `503` | `reconcile_status_unavailable` | Coverbase cannot read the rebuild's status right now. Try again shortly. |
| `409` | `accounts_gone` | An account was removed while you decided. Read the directory again. |
| `422` | `accounts_not_observed` | An account comes from Okta or Entra, which decides its owner. |
| `422` | `unknown_owner_not_assignable` | Clear the owner instead of assigning Unknown owner. |
| `422` | `merge_source_required` | Name at least one identity other than `into_identity_id`. |
| `422` | `directory_identity_not_mergeable` | An identity from Okta or Entra cannot be merged away. |
| `422` | `unknown_owner_not_mergeable` | Assign Unknown owner's accounts one at a time. |
| `422` | `platform_invalid` | The platform key is unknown. |

## Manage saved sign-in sessions

Inspect saves a sign-in session (an auth context) per single sign-on provider or application, and reuses it across runs. The API returns each session's `id`, `label`, `principal_login`, `status`, `allowed_domains`, `last_validated_at`, `last_stale_at`, `last_stale_reason`, and `last_error`. It never returns browser identifiers.

* To list them, send `GET /v1/inspect-auth-contexts`.
* To create the session for a provider, send `POST /v1/inspect-auth-contexts` with optional `label`, `provider_config`, and `allowed_domains`. Leave out `provider_config` for Okta. When a session for the provider exists, Coverbase returns it. The session starts empty, and Inspect signs in on the next run.
* To make Inspect sign in again, for example after a password change, send `POST /v1/inspect-auth-contexts/{auth_context_id}/stale` with an optional `reason`.
* To sign a single sign-on session in now, send `POST /v1/inspect-auth-contexts/{auth_context_id}/bootstrap`. It returns `202` with the session, and the sign-in runs in the background. A sign-in already under way comes back as it is. An application's session signs in only when an inspection reaches its sign-in page, so the call returns `422`.

Listing needs `integration:read:org`. Creating and flagging need `integration:update:org`. Signing in now needs `integration:run:org`.

### Errors

| Status | Code | Meaning |
| - | - | - |
| `404` | `auth_context_not_found` | No session with this ID in your organization. |
| `409` | `auth_context_provider_unavailable` | The provider is not connected or has no inspection identity. |
| `409` | `auth_context_not_ready` | The provider has no active inspection identity or stored password yet. |
| `422` | `auth_context_bootstrap_unsupported` | An application's session signs in during a run, not on its own. |
| `422` | `auth_context_config_invalid` | `provider_config` is not valid for the provider. |
| `502` | `browser_profile_unavailable` | Coverbase could not create the browser profile. Try again. |

## Find documentation for a control

Inspect builds plans from vendor documentation for each platform.

* To list the documents for an application's platform, send `GET /v1/inspect-applications/{application_id}/documentation`. The response has `platform_key`, `bundle_id`, `activated_at`, and `documents`, each with `key`, `title`, `usage`, and `canonical_url`. An application without a platform has no documents.
* To search for the documentation a control needs, send `POST /v1/inspect-documentation-discovery-runs` with `control_id` and `application_id`. It returns `202` with the run. A run already queued for the same pair is returned instead of a new one.
* To follow a run, send `GET /v1/inspect-documentation-discovery-runs/{run_id}`. The run has `id`, `control_id`, `application_id`, `platform_key`, `status`, `phase`, `outcome`, `failure_code`, `resource_bundle_id`, `created_at`, `started_at`, and `finished_at`.
* To read one document's text, send `GET /v1/inspect-applications/{application_id}/documentation/{document_key}` with a `key` from the list. The response has `key`, `title`, `media_type`, `text`, and `truncated`, which is true when the text stopped at one million characters.

Reads need `integration:read:org`. Starting a run needs `integration:run:org`.

### Errors

| Status | Code | Meaning |
| - | - | - |
| `404` | `application_not_found` | No application with this ID in your organization. |
| `404` | `control_not_found` | No control with this ID in your organization. |
| `404` | `target_not_found` | No application with this ID in your organization. |
| `404` | `discovery_run_not_found` | No discovery run with this ID. |
| `404` | `document_not_found` | The platform's documents have no document with this key. |
| `503` | `documentation_storage_unavailable` | Coverbase cannot read documents right now. |
| `422` | `target_archived` | The application is archived. |
| `422` | `target_platform_missing` | The application has no platform. |

## Read Okta and Entra connections

* To list the applications synced from Okta, send `GET /v1/okta-integration/applications`. For Microsoft Entra, send `GET /v1/entra-integration/applications`. Both take `limit` (1 to 500, default 100) and `offset`. Each item has `id`, `provider_app_id`, `display_name`, `status`, `sign_on_mode`, `login_url`, `platform_key`, `vendor_id`, and `last_synced_at`.
* To read how often Coverbase syncs Okta, send `GET /v1/okta-integration/schedule`. The response has `connected`, `sync_interval_hours`, `last_synced_at`, and `next_sync_at`.
* To change it, send `PUT /v1/okta-integration/schedule` with `sync_interval_hours` set to `6`, `12`, `24`, or `168`, or null to sync only when someone asks.
* To read the latest sync, send `GET /v1/okta-integration/sync`. The response has `job`, which is null when Okta never synced. A job has `id`, `kind`, `status`, `stage`, `incremental`, `inventory_ready`, `applications_ready`, `applications_total`, `access_synced_count`, `groups_synced_count`, `can_resume`, record counts, `last_error`, `started_at`, and `completed_at`. A sync that stopped reporting progress reads as `failed`.
* To disconnect Okta, send `DELETE /v1/okta-integration`. Inspect stops syncing it and keeps the synced history. It returns `204`.
* To sync Okta now, send `POST /v1/okta-integration/sync` with optional `resume` (continue the last failed sync) and `full` (reread everything). It returns `202` with `sync_job_id` and `status`. A sync already running comes back instead of a new one. Poll `GET /v1/okta-integration/sync`.
* To check the connection against Okta, send `POST /v1/okta-integration/verify`. The response has `status` (`connected` or `error`), `error_category`, `remediation_hint`, and `requirements`, each with `id`, `label`, `status`, and `detail`.
* To compare the scopes Inspect needs with the ones your Okta app granted, send `GET /v1/okta-integration/scopes`. The response has `requested_scopes`, `granted_scopes`, and `missing_scopes`.
* To read one Okta application, send `GET /v1/okta-integration/applications/{application_id}`. The response has its sign-on mode, whether Inspect can sign in to it, its assignment count, and its vendor link. It leaves out the raw Okta record, which can hold credentials. To list who is assigned to it, send `GET /v1/okta-integration/applications/{application_id}/users`.
* To list the people in your Okta directory with their application accounts and findings, send `GET /v1/okta-integration/identities` with `limit` (1 to 500, default 100) and `offset`. For counts only, send `GET /v1/okta-integration/identities/summary`.
* To read the Okta user Inspect signs in as, send `GET /v1/okta-integration/inspection-identity`. The response has `login`, `status`, `credentials_configured`, `grants`, `recent_actions`, `manual_steps`, and `write_allowed`. It says whether a password is stored and never returns it.
* To provision that user and assign it to applications, send `POST /v1/okta-integration/provision` with `application_ids`, an optional `login`, and `approved: true`. To remove its access, send `POST /v1/okta-integration/deprovision` with `approved: true`, and `delete_user: true` to delete the Okta user too. Both return `202` and run in the background.
* To check every Okta application Inspect can sign in to, send `POST /v1/okta-integration/inspect-runs`. It returns `202` with the run. Poll `GET /v1/okta-integration/inspect-runs/{run_id}`, which adds each application's result.
* For Microsoft Entra, send `POST /v1/entra-integration/verify` to check the Microsoft Graph permissions, and `POST /v1/entra-integration/sync` to sync applications, people, and assignments. The sync finishes before the call returns. To read the Entra user Inspect signs in as, send `GET /v1/entra-integration/inspection-identity`. To provision it, send `POST /v1/entra-integration/provision` with `application_ids`, an optional `user_principal_name`, and `approved: true`.

Provisioning and deprovisioning change access in your identity provider. Only an organization admin can do them, and API keys cannot. Syncing, verifying, and starting an inspect run also stay with an organization admin.

Changing the schedule and disconnecting stay with an organization admin, so API keys cannot do them. You connect Okta and Entra, store their credentials, and rotate Okta keys in Coverbase.

### Errors

| Status | Code | Meaning |
| - | - | - |
| `403` | `admin_required` | The caller is not an organization admin, or is an API key. |
| `403` | `api_key_not_allowed` | An API key tried to disconnect Okta. |
| `404` | `okta_not_connected` | Okta is not connected for your organization. |
| `400` | `approval_required` | Send `approved: true` to change access in your identity provider. |
| `403` | `api_key_not_allowed` | An API key tried to provision or deprovision. |
| `403` | `okta_writes_not_permitted` | Coverbase does not write to this Okta organization. |
| `404` | `okta_application_not_found` | No Okta application with this ID. |
| `404` | `okta_run_not_found` | No Okta inspect run with this ID. |
| `404` | `inspection_identity_not_found` | There is no inspection identity to deprovision. |
| `404` | `entra_not_connected` | Microsoft Entra is not connected for your organization. |
| `409` | `entra_secret_not_configured` | The Entra client secret is not stored. Add it in Coverbase. |
| `409` | `okta_operation_running` | Another Okta sync or provisioning run is still running. |
| `409` | `okta_sync_running` | Wait for the Okta sync to finish before changing provisioning. |
| `409` | `okta_provisioning_in_progress` | Provisioning is already running. |
| `409` | `okta_sync_not_resumable` | There is no failed sync with saved progress to resume. |
| `422` | `okta_application_not_drivable` | Inspect cannot sign in to this application's sign-on mode. |
| `502` | `entra_sync_failed` | Microsoft Graph refused the sync. The job is marked failed. |
| `502` | `entra_provisioning_failed` | Microsoft Graph refused a provisioning step. |
| `503` | `okta_run_check_unavailable` | Coverbase could not check for other Okta runs. Try again shortly. |

## Watch or download a control run's browser

When Inspect checks a control in a browser, it records each browser tab.

* To list a run's recorded tabs, send `GET /v1/inspections/{inspection_id}/runs/{run_id}/replay`. The response has `status` (`ready`, `preparing`, or `unavailable`) and `pages`, each with `page_id`. A recording reads as `preparing` for about a minute after the run finishes.
* To download one tab, send `GET /v1/inspections/{inspection_id}/runs/{run_id}/replay/pages/{page_id}`. The response is an HLS playlist (`application/vnd.apple.mpegurl`) whose segment links are short-lived, so play or save it right away.
* To watch a running control, send `GET /v1/inspections/{inspection_id}/runs/{run_id}/live-view`. The response has `live_view_url` and `pages`, each with `page_id`, `title`, and `live_view_url`. The fields are null when the control is not running. Anyone with a live view link can watch until it expires, so do not store or share it.

These responses are never cached. All three need `integration:read:org`.

### Errors

| Status | Code | Meaning |
| - | - | - |
| `404` | `replay_not_found` | The run is not in this inspection, never opened a browser, or the tab has no recording. |
| `404` | `run_not_found` | The run is not in this inspection. |
| `502` | `replay_provider_unavailable` | The recording provider is unavailable. Try again shortly. |

## Run probes

A probe is a custom check Inspect runs on one application, once as a preview or on a schedule. Each run is a sample.

1. To draft a probe, send `POST /v1/inspect-probes/prepare` with `target_id` (the application), `objective`, and an optional `name`. Inspect plans checkpoints from the platform's documentation. Nothing is saved.
2. To save the draft, send `POST /v1/inspect-probes` with the draft's `draft_id`, `target_id`, `name`, `resource_bundle_id`, and `spec`, and an optional `interval_seconds` (900 to 604800, default 3600). It returns `201` with the probe, paused.
3. To run a sample now, send `POST /v1/inspect-probes/{probe_id}/preview` with an `idempotency_key`. It returns `202` with the sample's `inspection_id` and `run_id`. Sending the same key again returns the first sample.
4. To turn on its schedule, send `PATCH /v1/inspect-probes/{probe_id}/automation` with `enabled: true` and an optional `interval_seconds`. Inspect needs a reviewed preview of the current procedure and every requirement ready, or the call returns `409`.

To change the procedure, send `POST /v1/inspect-probes/{probe_id}/versions` with `expected_version` (the `version` you read), `resource_bundle_id`, and `spec`. When someone published since, it returns `409`.

* To list probes, send `GET /v1/inspect-probes` with an optional `application_id`, `limit` (1 to 100, default 25), and `offset`. To filter them, send `POST /v1/inspect-probes/query` with `filter`, `sort`, `search`, `application_id`, `limit`, and `offset`. The response has `probes` and `total`.
* To read one probe with its procedure, readiness, automation, and latest sample, send `GET /v1/inspect-probes/{probe_id}`.
* To list samples, send `GET /v1/inspect-probes/{probe_id}/runs`. To read one sample with each checkpoint's result and its evidence, send `GET /v1/inspect-probes/{probe_id}/runs/{run_id}`.
* To keep a sample for an auditor, send `GET /v1/inspect-probes/{probe_id}/runs/{run_id}/package`. It returns a zip with a manifest, a printable summary, and the screenshots. `X-Missing-Screenshots` counts screenshots Coverbase could not read. The response is never cached.
* To see each scheduled launch and whether a sample started, send `GET /v1/inspect-probes/{probe_id}/deliveries` with optional `before`, `after`, `exclude_accepted`, and `limit`.

The `definitions` routes are deprecated. New probes do not need a definition.

### Errors

| Status | Code | Meaning |
| - | - | - |
| `404` | `probe_not_found` | No probe with this ID in your organization. |
| `404` | `probe_sample_not_found` | No sample with this ID on this probe. |
| `409` | `probe_conflict` | The probe changed since you read it, or it is not ready to automate. |
| `409` | `probe_sample_has_no_evidence` | The sample has no evidence to package yet. |
| `409` | `probe_sample_too_large` | The sample's screenshots are too large to package. |
| `422` | `probe_invalid` | The draft, procedure, or interval is not valid. |

## Raise an evaluation as a Finding

When an Inspect evaluation fails, you can raise it as a Finding.

* Send `POST /v1/inspect-evaluations/{evaluation_id}/finding`. A new Finding returns `201` with `finding` and `created: true`, and Coverbase drafts its recommended remediation in the background. When the evaluation already raised one, the call returns `200` with that Finding and `created: false`. It needs `finding:create:org`.
* To draft the recommended remediation for a Finding Inspect raised whose guidance is empty, send `POST /v1/findings/{finding_id}/recommended-remediation/draft`. It returns `202`. Guidance someone wrote or cleared is never replaced, so the call returns `409`. It needs `finding:update:org`.
* To read the guidance, send `GET /v1/findings/{finding_id}/recommended-remediation`. The response has `status` (`available`, `drafting`, `cleared`, or `absent`) and `recommended_remediation`. It needs `finding:read:org`.

### Errors

| Status | Code | Meaning |
| - | - | - |
| `404` | `evaluation_not_found` | No evaluation with this ID in your organization. |
| `404` | `finding_not_found` | No Finding with this ID in your organization. |
| `409` | `remediation_already_written` | The Finding's guidance was written or cleared. |
| `422` | `evaluation_cannot_raise_finding` | Only a completed, flagged evaluation whose run finished can become a Finding. |
| `422` | `finding_not_from_inspect` | Only a Finding raised from an Inspect evaluation can be drafted. |

## Poll an operation's events

Inspect logs each step of a run, a sign-in, a plan preparation, or a documentation search. To read the log, send `GET /v1/inspect-events` with exactly one of `run_id`, `auth_context_id`, `application_id`, `plan_preparation_id`, or `documentation_discovery_run_id`. Events come oldest first, up to `limit` (1 to 500, default 500). To read only newer events, pass the last `sequence` you read as `after_sequence`. This replaces the dashboard's live stream. It needs `integration:read:org`.

| Status | Code | Meaning |
| - | - | - |
| `404` | `event_anchor_not_found` | Nothing with this ID in your organization. |
| `422` | `event_anchor_invalid` | Name exactly one anchor. |

## Decide an access removal request

A workflow can propose removing identity provider assignments from a vendor's users. Approving one stays in Coverbase.

* To reject a request, send `POST /v1/access-removal-requests/{request_id}/reject` with an optional `reason`.
* To close a request after a person removed the rows in the identity provider, send `POST /v1/access-removal-requests/{request_id}/complete-manually` with the `item_ids` they removed.

Both return the request. Deciding who keeps access stays with a person, so API keys cannot do either. When the request names approvers, you must be one. Both need `integration:update:org`.

| Status | Code | Meaning |
| - | - | - |
| `403` | `api_key_not_allowed` | An API key tried to decide a request. |
| `404` | `access_removal_request_not_found` | No request with this ID in your organization. |
| `409` | `access_removal_not_decidable` | The request is already decided, you are not one of its approvers, or the rows are not valid. |

## Export, import, and test insight definitions

* To export your insight library, send `GET /v1/document-insight-definitions` with an optional `include_archived`. Each item is a portable definition keyed by `field_key`, with no ids and no extracted values.
* To import definitions, send `POST /v1/document-insight-definitions` with `definitions` (up to 500) and an optional `overwrite_existing` (default `false`). An insight whose `field_key` already exists is skipped unless you overwrite. The response lists `created_field_keys`, `updated_field_keys`, and `skipped_field_keys`.
* To try a definition before saving it, send `POST /v1/document-insight-definitions/test` with `field_name` and any of `field_description`, `field_type`, `field_mode`, `document_types`, `sample_size` (1 to 5), `config_id`, and `document_ids`. It runs one model call per document and saves nothing. Each item gives the answer, its quote, and, with `config_id`, whether it matches the value the insight holds now. A scope with no readable documents returns `422` with `no_documents_to_test`.

## Delete a document insight

Deleting removes the insight and every value it ever extracted. It cannot be undone, so it takes two steps.

1. Archive the insight with `POST /v1/document-insights/{config_id}/archive`.
2. Send `GET /v1/document-insights/{config_id}/delete-preview`. The response gives `extracted_value_count` and `linked_custom_field_names`.
3. Send `DELETE /v1/document-insights/{config_id}?acknowledged_value_count=N`, where `N` is the count the preview gave. It returns `204`.

API keys cannot delete an insight. An insight that is not archived returns `409` with `insight_not_archived`, a count that changed returns `409` with `value_count_changed`, and an insight that still fills a custom field returns `409` with `linked_custom_fields`. Unlink those fields first.

## Read value history and coverage

* To read every value change for one insight, newest first, send `GET /v1/document-insights/{config_id}/events` with `limit` (1 to 200) and `offset`. For one value's timeline, send `GET /v1/document-insight-values/{data_id}/events`. Each item gives `event_type`, `trigger`, `actor_name`, `document_name`, `before`, and `after`.
* To read every recorded revision of a definition, send `GET /v1/document-insights/{config_id}/revisions`.
* To read the coverage matrix, send `GET /v1/document-insight-coverage` with optional `document_type` and `config_id`, each repeatable. `rows` gives each document type's totals, and `cells` gives each insight's `eligible`, `filled`, `grounded`, `needs_review`, `never_attempted`, and `fill_rate` per type.
* To see what waits for a person, send `GET /v1/document-insight-inbox`. It counts `field_changes`, `disagreements`, `unverified_evidence`, and `accuracy_misses`.
* To list the built-in contract and document fields an insight can fill, send `GET /v1/document-insight-target-fields`.

## Browse and compare extracted values

* To filter every value in your organization, send `POST /v1/document-insight-values/query` with any of `config_ids`, `document_types`, `vendor_ids`, `source_type`, `confidence`, `grounded`, `needs_review`, `has_value`, `search`, `verdict`, `outdated`, `config_revision`, `limit` (1 to 200), and `offset`.
* To compare values side by side, send `POST /v1/document-insight-values/pivot` with `document_types` (1 to 20) and optional `config_ids`, `vendor_ids`, `search`, `limit`, and `offset`. Each row is a document, and `cells` maps each insight ID to its value. A missing key means nothing was extracted.

### Evidence images

* To list a value's verified citations, send `GET /v1/document-insight-values/{data_id}/snippets`. Each item gives `evidence_fingerprint`, the quote and page, and `status`. A `rendered` citation carries a presigned `url` to its page image, valid for `expires_in` seconds. Follow it with a plain `GET` and no auth header.
* To render a citation's image, send `POST /v1/document-insight-values/{data_id}/snippets` with `evidence_fingerprint`. It returns `queued` and renders in the background. List the snippets again for the link. A fingerprint that matches no current citation returns `404` with `citation_not_found`.

## Export an insight's values

* To list the columns an export can hold, send `GET /v1/document-insight-export-columns`.
* To export, send `POST /v1/document-insights/{config_id}/export` with any of `columns`, `data_ids`, the value filters, `include_empty`, and `multi_value_mode`. The response gives a presigned `url` to the workbook, `filename`, `expires_in`, `exported_rows`, and `available_rows`. Every export is recorded on the insight's activity.

These responses are never cached.

## Check a decision model's accuracy

* To read a check's scorecard, send `GET /v1/document-insight-models/{model_id}/scorecard`. It gives `base`, `candidate`, and `shadow` scores, overall and per insight, with reviews applied.
* To work through the misses, send `GET /v1/document-insight-models/{model_id}/examples` with optional `role`, `config_id`, `outcome`, `reviewed`, `limit`, and `offset`.
* To settle one miss, send `POST /v1/document-insight-eval-examples/{example_id}/review` with `decision` (`team_right`, `ai_right`, `both_fine`, or null to clear). `ai_right` also corrects the checked value to the AI's answer, which needs `vendor:update` on that vendor.
* To see one insight's training set, send `GET /v1/document-insight-models/{model_id}/dataset-preview?config_id=...` with an optional `status` (`train`, `holdout`, `used_as_example`, or `no_evidence`).
* To answer live documents with a trained model beside production, send `PUT /v1/document-insight-models/{model_id}/shadow` with `enabled`. Only one model shadows at a time, and nothing it answers is saved. A model that is not trained and ready returns `409` with `shadow_unavailable`.

## Run an insight on a document

* To run a saved insight on one document, send `POST /v1/documents/{document_id}/insight-extractions` with `config_id`. It costs one model call, returns the answer with its quote and confidence, and saves nothing.
* To try an unsaved definition, send `POST /v1/documents/{document_id}/insight-previews` with `field_name` and optional `field_description`, `field_type`, and `field_mode`. It returns `202` with a job. Poll `GET /v1/document-insight-previews/{job_id}` until `status` is `completed` or `failed`. Only the key or person that started a preview reads it.

## Retrain the document type model

Your organization's document type model is a fork of a shared base model. To read where both stand, send `GET /v1/document-type-decision-model`. To retrain your fork, send `POST /v1/document-type-decision-model/train-fork`. It returns `202`. A run already in progress returns `409` with `training_running`, and a missing base model returns `409` with `base_model_missing`. Without the feature, both return `404` with `document_type_model_not_enabled`.

## Reject a pending change

To reject a proposed field change, send `POST /v1/document-insight-pending-changes/{change_id}/reject`. Nothing is written to the target record. An already resolved change returns `409` with `change_already_resolved`. API keys cannot approve or reject changes, so a signed-in person does it.

## Work an exposure

* To read one exposure, send `GET /v1/dark-web/exposures/{exposure_id}`. It adds the playbook, `baseline_item_id`, and `follow_up_finding_id` to the list fields. The matched value stays masked, and opening an exposure is audited. For its status history, send `GET /v1/dark-web/exposures/{exposure_id}/history`.
* To read its playbook, send `GET /v1/dark-web/exposures/{exposure_id}/playbook`. To tick or untick a step, send `PATCH` to the same path with `step_id` and `done`. A step that is not on the playbook returns `422` with `step_not_on_playbook`.
* To move many held exposures at once, send `POST /v1/dark-web/exposures/bulk-review` with `exposure_ids` (up to 200), `action` (`promote` or `dismiss`), and, to dismiss, `false_positive_reason`. Only exposures still in Needs review move. The rest come back in `skipped` with `not_found` or `not_in_needs_review`.
* To read evidence, send `GET /v1/dark-web/exposures/{exposure_id}/evidence`. Each capture gives its metadata and a presigned `download_url` for the redacted capture, valid for `expires_in` seconds. The content is never inline, every read is audited, and the response is never cached.
* To start a follow-up with a partner, send `POST /v1/dark-web/exposures/{exposure_id}/partner-follow-up` with optional `title`, `assigned_to_id`, and `note`. It opens a finding on the exposure's vendor, or on the partner a program BIN runs for. It does not contact the partner: whether and how the partner hears stays your decision. A second call returns the open finding with `created` set to `false`.
* To read one vendor's dark web picture, send `GET /v1/dark-web/vendors/{vendor_id}`.

Recording consent and sending an exposure to Legal never go through the API.

## Run the dark web program

* To run a sweep now, send `POST /v1/dark-web/sweeps`. It returns `202`. One sweep runs at a time, so a second call returns `active_run_id`. To list sweeps, send `GET /v1/dark-web/sweeps`.
* To read the setup checklist, send `GET /v1/dark-web/setup`. To record that a person reviewed the alert rules or the business hours, send `POST /v1/dark-web/setup/confirm/{confirmation}` with `alert_rules_reviewed` or `business_hours`. API keys cannot confirm a step.
* To preview a retention change, send `GET /v1/dark-web/retention/preview` with any of `exposures_years`, `evidence_years`, `audit_years`, and `sweep_history_years`. It counts what the next purge removes and gives `next_purge_at`.
* To read the program report, send `GET /v1/dark-web/report` with `from_ts`, `to_ts`, and optional `time_zone`. It returns aggregates only. Each read is audited.
* To export the queue, send `POST /v1/dark-web/exposures/export` with the queue filters. The response gives a presigned `url` to a CSV with no summary, matched value, or evidence. More than the export limit returns `413` with `export_too_large`.
* To read the sources, send `GET /v1/dark-web/sources`. To read the managed AI fraud terms, send `GET /v1/dark-web/ai-fraud-terms`.

### Baseline

The baseline is the list of exposures your organization already knew about.

* To read a file's columns, send `POST /v1/dark-web/baseline/preview` as `multipart/form-data` with `file` (`.csv` or `.xlsx`). It suggests a mapping and stores nothing.
* To import, send `POST /v1/dark-web/baseline/import` as `multipart/form-data` with `file`, `mapping` (a JSON object from each baseline field to a column), and `dry_run`. `dry_run` defaults to `true`, so send `false` to keep the import. A re-import replaces every item.
* To read the baseline, send `GET /v1/dark-web/baseline`. Identifiers are masked.

### Alert rules

* To list the rules in evaluation order, send `GET /v1/dark-web/alert-rules`.
* To add one, send `POST /v1/dark-web/alert-rules` with the whole rule: `name`, `is_enabled`, `applies_in_addition`, `match`, `recipients`, `channels`, `clock`, and `escalation`. To replace one, send `PATCH /v1/dark-web/alert-rules/{rule_id}` with the whole rule. To set the order, send `PUT /v1/dark-web/alert-rules/order` with `rule_ids`. These need an organization admin.
* To see how often a rule would have fired, send `POST /v1/dark-web/alert-rules/preview` with `match`. It counts exposures first seen in the last 30 days.
* To check your SIEM's parser, send `POST /v1/dark-web/alert-rules/test`. It sends a fictional, signed `DarkWebExposure.Created` to every webhook subscribed to dark web events, so it contacts your webhook endpoints.

### Access

To read the roles that open dark web monitoring and what each can do, send `GET /v1/dark-web/access`. To create the designated roles your organization is missing, send `POST /v1/dark-web/access/roles`. It never changes a role that exists. API keys never change roles.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.