> ## 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.

# Platform configuration API

> Manage statuses, custom fields and sections, email templates and layouts, notifications, saved views, workflows, Coverbase AI agents, runs and preferences, reports, RFPs, billing and the TPRM lifecycle configuration.

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 let you manage your organization's configuration: the **status** options each record type moves through, **custom field sections**, **email templates**, **workflow definitions**, **Coverbase AI agents** and their **preferences**, **reports**, and the **TPRM lifecycle configuration** that names your TPRM Office and decides who past-due vendor reminders copy.

All endpoints are org-scoped to the API key. See [API conventions](/conventions.md) for shared behavior. For custom fields, see the [Custom fields API](/api-reference/custom-fields.md). For workflows, see the [Workflows API](/api-reference/workflows.md).

| Method | Path | Permission |
| - | - | - |
| `GET` | `/v1/statuses` | `org_settings:read:org` |
| `POST` | `/v1/statuses` | `org_settings:update:org` |
| `PATCH` | `/v1/statuses/{status_id}` | `org_settings:update:org` |
| `GET` | `/v1/tprm-lifecycle-config` | `org_settings:read:org` |
| `PUT` | `/v1/tprm-lifecycle-config` | `org_settings:update:org` |
| `GET` | `/v1/custom-field-sections` | `custom_field:read:org` |
| `POST` | `/v1/custom-field-sections` | `custom_field:create:org` |
| `PATCH` | `/v1/custom-field-sections/{section_id}` | `custom_field:update:org` |
| `GET` | `/v1/email-templates` | `email_template:read:org` |
| `POST` | `/v1/email-templates` | `email_template:create:org` |
| `PATCH` | `/v1/email-templates/{email_template_id}` | `email_template:update:org` |
| `GET` | `/v1/workflow-definitions/{workflow_definition_id}` | `workflow:read:org` |
| `PATCH` | `/v1/workflow-definitions/{workflow_definition_id}` | `workflow:update:org` |
| `GET` | `/v1/workflow-definitions/{workflow_definition_id}/versions` | `workflow:read:org` |
| `GET` | `/v1/workflow-definitions/{workflow_definition_id}/schedules` | `workflow:read:org` |
| `POST` | `/v1/workflow-schedules/{schedule_id}/cancel` | `workflow:update:org` |
| `GET` | `/v1/workflow-templates` | `workflow:read:org` |
| `POST` | `/v1/workflow-templates/{template_slug}/apply` | `workflow:create:org` |
| `GET` | `/v1/rules` | `org_settings:read:org` |
| `POST` | `/v1/rules` | `org_settings:update:org` |
| `PATCH` | `/v1/rules/{rule_id}` | `org_settings:update:org` |
| `GET` | `/v1/agents` | `org_settings:read:org` |
| `POST` | `/v1/agents/{agent_id}/pause` | `org_settings:update:org` |
| `POST` | `/v1/agents/{agent_id}/resume` | `org_settings:update:org` |
| `GET` | `/v1/agent-templates` | `org_settings:read:org` |
| `POST` | `/v1/agents/from-template` | `org_settings:update:org` |
| `PUT` | `/v1/agents/paused` | `org_settings:update:org` |
| `GET` | `/v1/agent-tool-policies` | `org_settings:update:org` |
| `PATCH` | `/v1/agent-tool-policies` | `org_settings:update:org` |
| `GET` | `/v1/agent-preferences` | `org_settings:read:org` |
| `POST` | `/v1/agent-preferences` | `org_settings:update:org` |
| `PATCH` | `/v1/agent-preferences/{preference_id}` | `org_settings:update:org` |
| `GET` | `/v1/reports` | `report:read:org` |
| `GET` | `/v1/reports/{report_id}` | `report:read:org` |
| `POST` | `/v1/reports` | `report:create:org` |
| `POST` | `/v1/reports/{report_id}/clone` | `report:create:org` |
| `PATCH` | `/v1/reports/{report_id}` | `report:update:org` |
| `GET` | `/v1/report-templates` | `report:read:org` |
| `GET` | `/v1/roles` | `role:read:org` |
| `GET` | `/v1/org-settings` | `org_settings:read:org` |
| `PATCH` | `/v1/org-settings` | `org_settings:update:org` |
| `GET` | `/v1/document-type-settings` | `org_settings:read:org` |
| `POST` | `/v1/document-type-settings/set-enabled` | `org_settings:update:org` |
| `GET` | `/v1/autofillable-fields` | `custom_field:read:org` |
| `GET` | `/v1/summary-instructions` | `org_settings:read:org` |
| `POST` | `/v1/summary-instructions` | `org_settings:update:org` (org admin) |
| `POST` | `/v1/summary-instructions/{prompt_id}/revisions` | `org_settings:update:org` (org admin) |
| `GET` | `/v1/conditions` | `workflow:read:org` |
| `GET` | `/v1/workflow-metadata` | `workflow:read:org` |
| `GET` | `/v1/workflow-components` | `workflow:read:org` |
| `POST` | `/v1/workflow-components` | `workflow:update:org` |
| `PATCH` | `/v1/workflow-components/{component_id}` | `workflow:update:org` |
| `POST` | `/v1/agents` | `org_settings:update:org` |
| `PATCH` | `/v1/agents/{agent_id}` | `org_settings:update:org` |
| `GET` | `/v1/reports/{report_id}/audience` | `report:read:org` |
| `PUT` | `/v1/reports/{report_id}/audience` | `report:update:org` |
| `GET` | `/v1/report-charts` | `report:read:org` |
| `GET` | `/v1/report-charts/{chart_id}` | `report:read:org` |
| `POST` | `/v1/report-charts` | `report:create:org` |
| `PATCH` | `/v1/report-charts/{chart_id}` | `report:update:org` |
| `POST` | `/v1/chart-statistics` | `report:read:org` |
| `POST` | `/v1/program-insights` | `report:read:org` |
| `GET` | `/v1/performance-rubrics` | `vendor:read:org` |
| `POST` | `/v1/performance-rubrics` | `vendor:update:org` |
| `PATCH` | `/v1/performance-rubrics/{rubric_id}` | `vendor:update:org` |
| `POST` | `/v1/performance-rubrics/{rubric_id}/components` | `vendor:update:org` |
| `PATCH` | `/v1/performance-components/{component_id}` | `vendor:update:org` |
| `POST` | `/v1/performance-rubrics/{rubric_id}/groups` | `vendor:update:org` |
| `PATCH` | `/v1/performance-groups/{group_id}` | `vendor:update:org` |
| `GET` | `/v1/performance-scores` | `vendor:read:org` |
| `POST` | `/v1/performance-scores` | `vendor:update:org` |
| `GET` | `/v1/dashboard-templates` | `report:read:org` |
| `POST` | `/v1/dashboard-templates/{template_slug}/apply` | `report:create:org` |
| `POST` | `/v1/reports/{report_id}/chart-templates` | `report:update:org` |
| `POST` | `/v1/reports/{report_id}/exports` | `report:export:org` |
| `GET` | `/v1/report-exports/{export_id}` | `report:export:org` |
| `GET` | `/v1/recent-activity` | `vendor:read:org` |
| `GET` | `/v1/workflow-definitions/{workflow_definition_id}/graph-issues` | `workflow:read:org` |
| `GET` | `/v1/workflow-definitions/{workflow_definition_id}/versions/diff` | `workflow:read:org` |
| `PATCH` | `/v1/custom-document-types/{custom_document_type_id}` | `org_settings:update:org` |
| `POST` | `/v1/custom-document-types/draft` | `org_settings:update:org` |
| `POST` | `/v1/custom-document-types` | `org_settings:update:org` |
| `POST` | `/v1/custom-document-types/{custom_document_type_id}/examples` | `org_settings:update:org` |
| `POST` | `/v1/custom-document-types/{custom_document_type_id}/lookalikes/{vendor_document_id}/decision` | `org_settings:update:org` |
| `GET` | `/v1/prompts/{prompt_name}/versions` | `org_settings:read:org` |
| `PUT` | `/v1/prompts/{prompt_name}` | `org_settings:update:org` |
| `POST` | `/v1/prompts/{prompt_name}/select` | `org_settings:update:org` |
| `PATCH` | `/v1/prompts/{prompt_name}/versions/{version_num}` | `org_settings:update:org`; archiving needs a user key |
| `GET` | `/v1/agent-playbooks` | Any member |
| `GET` | `/v1/agent-setup` | Any member |
| `POST` | `/v1/agent-runs` | Any member; `approval_policy: auto` needs a user key |
| `GET` | `/v1/agent-runs` | Any member, own runs only |
| `GET` | `/v1/agent-runs/{run_id}` | Any member, own runs only |
| `GET` | `/v1/agent-runs/{run_id}/history` | Any member, own runs only |
| `GET` | `/v1/agent-runs/{run_id}/export` | Any member, own runs only |
| `POST` | `/v1/agent-runs/{run_id}/answer` | Any member, own runs only; accepting or rejecting a proposal needs a user key |
| `POST` | `/v1/agent-runs/{run_id}/instruct` | Any member, own runs only; withdrawing a proposal needs a user key |
| `POST` | `/v1/agent-runs/{run_id}/stop` | Any member, own runs only |
| `POST` | `/v1/agent-runs/{run_id}/mode` | Any member, own runs only |
| `GET` | `/v1/billing-overview` | `billing:read:org` |
| `GET` | `/v1/rfp-categories` | `rfp:read:org` |
| `PATCH` | `/v1/rfp-records/{rfp_id}` | `rfp:update:org` |
| `POST` | `/v1/rfp-records/{rfp_id}/set-status` | `rfp:update:org`; `archived` and `awarded` need a user key |
| `POST` | `/v1/rfp-records/{rfp_id}/pause` | `rfp:update:org` |
| `POST` | `/v1/rfp-records/{rfp_id}/cancel` | `rfp:update:org` |
| `POST` | `/v1/rfp-records/{rfp_id}/submissions/rank` | `rfp_evaluation:update:org` |
| `POST` | `/v1/rfp-records/{rfp_id}/lock-rubric` | `rfp:update:org` |
| `GET` | `/v1/rfp-records/{rfp_id}/invitations` | `rfp:read:org` |
| `PATCH` | `/v1/rfp-records/{rfp_id}/invitations/{invitation_id}` | `rfp:update:org` |
| `GET` | `/v1/rfp-records/{rfp_id}/submissions` | `rfp:read:org` |
| `POST` | `/v1/rfp-records/{rfp_id}/submissions` | `rfp:update:org` |
| `GET` | `/v1/workflow-definitions` | `workflow:read:org` |
| `GET` | `/v1/lifecycle-requirements` | `workflow:read:org` |
| `GET` | `/v1/integrations` | `integration:read:org` |
| `PUT` | `/v1/integrations/{provider}/status` | `integration:update:org` |
| `PUT` | `/v1/integrations/{provider}/mappings` | `integration:update:org` |
| `POST` | `/v1/integrations/{provider}/syncs` | `integration:run:org` |
| `GET` | `/v1/integrations/{provider}/sync-runs` | `integration:read:org` |
| `GET` | `/v1/integrations/{provider}/sync-records` | `integration:read:org` |
| `GET` | `/v1/integration-conflicts` | `integration:read:org` |
| `POST` | `/v1/integration-conflicts/{conflict_id}/resolve` | `integration:update:org` |
| `POST` | `/v1/integration-conflicts/{conflict_id}/dismiss` | `integration:update:org` |
| `POST` | `/v1/integration-conflicts/bulk-jobs` | `integration:update:org` |
| `GET` | `/v1/integration-conflicts/bulk-jobs/{job_id}` | `integration:read:org` |
| `GET` | `/v1/integration-mismatches` | `integration:read:org` |
| `POST` | `/v1/integration-mismatches/{mismatch_id}/resolve` | `integration:update:org` |
| `GET` | `/v1/monitoring-cadence` | `org_settings:read:org` |
| `PUT` | `/v1/monitoring-cadence` | `org_settings:update:org` |
| `GET` | `/v1/monitoring-plans` | Vendor read access |
| `GET` | `/v1/monitoring-plans/{plan_id}` | Read access to the plan's engagement or vendor |
| `GET` | `/v1/monitoring-plans/{plan_id}/events` | Read access to the plan's engagement or vendor |
| `GET` | `/v1/engagements/{engagement_id}/monitoring-plan` | Read access to the engagement |
| `GET` | `/v1/services/{service_id}/monitoring-plan` | Read access to the service's vendor |
| `POST` | `/v1/engagements/{engagement_id}/monitoring-plan/generate` | TPRM Office (org-wide `vendor:update:org`) |
| `POST` | `/v1/services/{service_id}/monitoring-plan/generate` | TPRM Office (org-wide `vendor:update:org`) |
| `GET` | `/v1/monitoring-activities` | Vendor read access |
| `PATCH` | `/v1/monitoring-plans/{plan_id}/activities/{activity_id}` | TPRM Office (org-wide `vendor:update:org`) |
| `POST` | `/v1/monitoring-plans/{plan_id}/activities/{activity_id}/complete` | Update access to the plan's engagement or vendor |
| `GET` | `/v1/branding` | `org_settings:read:org` |
| `PATCH` | `/v1/branding` | `org_settings:update:org` |
| `PUT` | `/v1/branding/logo` | `org_settings:update:org` |
| `PUT` | `/v1/branding/icon` | `org_settings:update:org` |
| `GET` | `/v1/activity-log` | Read access to the record's type, such as `vendor:read:org` or `vendor:read:assigned`; `audit_trail:read:org` with no `target_type` or for a settings record |
| `GET` | `/v1/audit-log` | A user key, or an API key with the `audit:read` scope |
| `GET` | `/v1/audit-log/metadata` | A user key, or an API key with the `audit:read` scope |
| `GET` | `/v1/notes` | `note:read:org` and read access to the record |
| `POST` | `/v1/notes` | `note:create:org` and read access to the record |
| `PATCH` | `/v1/notes/{note_id}` | `note:update:org`; your own notes only |
| `GET` | `/v1/emails` | Read access to the record the email is about |
| `GET` | `/v1/emails/search` | Read access to the record the email is about |
| `GET` | `/v1/emails/{email_id}` | Read access to the record the email is about |
| `POST` | `/v1/emails` | Update access to the record the email is about |
| `GET` | `/v1/tprm-lifecycle-settings` | `org_settings:read:org` |
| `GET` | `/v1/template-variables` | `email_template:read:org` |
| `GET` | `/v1/risk-scales/default` | `org_settings:read:org` |
| `PUT` | `/v1/risk-scales/default/levels` | `org_settings:update:org` |
| `GET` | `/v1/home-dashboard` | `report:read:org` |
| `POST` | `/v1/reports/{report_id}/charts/{chart_id}/remove` | `report:update:org` |
| `POST` | `/v1/reports/{report_id}/scheduled-export/test` | `report:update:org` and `report:export:org` |
| `POST` | `/v1/performance-scores/from-response` | `vendor:update:org` |
| `GET` | `/v1/custom-fields/usage` | `custom_field:read:org` |
| `DELETE` | `/v1/custom-fields/values/{value_id}` | `custom_field:update:org` and update access to the record; needs a user key |
| `POST` | `/v1/directory-people` | `vendor:update:org` |
| `GET` | `/v1/roles/{role_id}/audit-log` | `role:read:org` |
| `GET` | `/v1/licensed-connectors` | `integration:read:org` |
| `GET` | `/v1/licensed-connectors/{connector}` | `integration:read:org` |
| `POST` | `/v1/licensed-connectors/{connector}/test` | `integration:run:org` |
| `GET` | `/v1/third-party-integrations/{provider}` | `integration:read:org` |
| `POST` | `/v1/third-party-integrations/slack/test-message` | `integration:run:org` |
| `POST` | `/v1/third-party-integrations/{provider}/test` | `integration:run:org`; `integration:update:org` for `screening` |
| `POST` | `/v1/jira-tickets` | `integration:run:org` |
| `GET` | `/v1/notification-settings` | Any member with a user key; your own settings only |
| `GET` | `/v1/notification-settings/{setting_id}` | Any member with a user key; your own settings only |
| `POST` | `/v1/notification-settings` | Any member with a user key; your own settings only |
| `PATCH` | `/v1/notification-settings/{setting_id}` | Any member with a user key; your own settings only |
| `GET` | `/v1/notification-types` | Any member with a user key |
| `GET` | `/v1/notification-preference` | Any member with a user key; your own preference only |
| `PUT` | `/v1/notification-preference` | Any member with a user key; your own preference only |
| `GET` | `/v1/notifications` | Any member with a user key; your own notifications only |
| `POST` | `/v1/notifications/mark-seen` | Any member with a user key; your own notifications only |
| `GET` | `/v1/saved-views` | Any member with a user key |
| `POST` | `/v1/saved-views` | Any member with a user key |
| `PATCH` | `/v1/saved-views/{saved_view_id}` | Any member with a user key; an admin for a shared view or the default |
| `GET` | `/v1/email-layouts` | `org_settings:read:org` |
| `POST` | `/v1/email-layouts` | `org_settings:update:org` |
| `POST` | `/v1/email-layouts/preview` | `org_settings:read:org` |
| `PATCH` | `/v1/email-layouts/{layout_id}` | `org_settings:update:org` |
| `GET` | `/v1/email-layouts/{layout_id}/preview` | `org_settings:read:org` |
| `POST` | `/v1/email-layouts/{layout_id}/dry-run` | `org_settings:update:org`; needs a user key |
| `POST` | `/v1/custom-fields` | `custom_field:create:org` |
| `PATCH` | `/v1/custom-fields/{custom_field_id}` | `custom_field:update:org` |

> [!NOTE]
>
> An organization API key can read roles, email templates and reports, and export reports. It does not hold the `org_settings` permissions, `email_template` write permissions, `report` create, update or archive permissions, `role` write permissions or `billing:read:org`. In an organization that enforces roles, call the routes that need them with a key created by a person whose role holds the permission.

None of these honor `Idempotency-Key`. An API key cannot archive a status, custom field section, email template, workflow, rule, report or agent preference. To archive one, use Coverbase. Every list endpoint takes `limit` (1 to 500, default 100) and `offset` (default 0) and returns `items`, `total`, `limit` and `offset`.

## Statuses

A **status** (`cbstatus_...`) is one option a record type can be in, for example a finding's "Awaiting vendor". Each record type has its own ordered list. Every status belongs to one of four groups: `unstarted`, `started`, `completed` or `canceled`.

The `target_type` names the record type. It is one of `assessment`, `procurement`, `engagement`, `vendor`, `service`, `contract_review`, `procurement_review`, `assessment_review`, `assessment_risk_domain_review`, `radar_signal_review`, `finding`, `rfp`, `contract`, `radar_event` or `dark_web_exposure`.

The `color` is one of `gray`, `green`, `red`, `yellow`, `blue`, `plum`, `orange`, `purple`, `brown` or `pink`. The `icon` is one of `circle`, `progress`, `check`, `subtract`, `close`, `flag`, `survey`, `question`, `clock` or `eye`.

### List statuses

**method** `GET`

`GET /v1/statuses`

Returns the statuses for one record type in display order.

**target\_type** `string` *required*

The record type to list statuses for.

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

Set to `true` to include archived statuses.

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

Maximum number of statuses to return, from 1 to 500.

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

Number of statuses to skip.

```bash cURL theme={null}
curl "https://api.coverbase.app/v1/statuses?target_type=finding" \
  -H "Authorization: Bearer ak_live_xxx"
```

The response has `items` (an array of [status objects](#status-object)), `total`, `limit` and `offset`.

### Create a status

**method** `POST`

`POST /v1/statuses`

Returns `201 Created` with the new [status object](#status-object). The new status goes to the end of the list unless you pass `sort_order`.

**target\_type** `string` *required*

The record type the status belongs to.

**label** `string` *required*

The name people see.

**color** `string` *required*

The status color.

**icon** `string` *required*

The status icon.

**description** `string` (default: "")

What the status means.

**group** `string` (default: unstarted)

`unstarted`, `started`, `completed` or `canceled`.

**sort\_order** `string`

A fractional order key. Copy one from a listed status to place the new status next to it.

**is\_default** `boolean` (default: false)

Set to `true` to make this the status new records start in.

**on\_standard\_path** `boolean` (default: true)

Whether the status is part of the normal progression.

**metadata** `object`

Settings specific to the record type.

```bash cURL theme={null}
curl -X POST "https://api.coverbase.app/v1/statuses" \
  -H "Authorization: Bearer ak_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "target_type": "finding",
    "label": "Awaiting vendor",
    "color": "yellow",
    "icon": "progress",
    "group": "started"
  }'
```

### Update a status

**method** `PATCH`

`PATCH /v1/statuses/{status_id}`

Returns the updated [status object](#status-object). Fields you omit keep their value. You cannot change a status where `system_managed` is `true`.

**status\_id** `string` *required*

The status ID (`cbstatus_...`).

The body takes the same fields as [Create a status](#create-a-status) except `target_type`. Every field is optional.

### Status object

**id** `string`

Status ID (`cbstatus_...`).

**target\_type** `string`

The record type.

**key** `string | null`

A stable reference for a built-in status. `null` for statuses your organization created.

**label** `string`

The name people see.

**color** `string`

The status color.

**icon** `string`

The status icon.

**description** `string`

What the status means.

**group** `string`

`unstarted`, `started`, `completed` or `canceled`.

**sort\_order** `string`

The fractional order key.

**is\_default** `boolean`

Whether new records start in this status.

**on\_standard\_path** `boolean`

Whether the status is part of the normal progression.

**is\_archived** `boolean`

Whether the status is archived.

**system\_managed** `boolean`

Whether Coverbase manages the status. You cannot change it.

**metadata** `object`

Settings specific to the record type.

**updated\_at** `integer`

Unix timestamp (seconds).

## TPRM lifecycle configuration

The TPRM lifecycle configuration names the user group that acts as your TPRM Office and decides who past-due vendor reminders copy. These endpoints return `404` when the TPRM lifecycle is not enabled for your organization.

### Get the configuration

**method** `GET`

`GET /v1/tprm-lifecycle-config`

Returns the [configuration object](#configuration-object). Before your organization saves a configuration, `is_configured` is `false` and every reminder setting is `true`.

```bash cURL theme={null}
curl "https://api.coverbase.app/v1/tprm-lifecycle-config" \
  -H "Authorization: Bearer ak_live_xxx"
```

### Replace the configuration

**method** `PUT`

`PUT /v1/tprm-lifecycle-config`

Returns the saved [configuration object](#configuration-object). This call sets every field. To keep the current TPRM Office, send its ID again.

**tprm\_office\_department\_id** `string`

The user group that is the TPRM Office. Omit it or send `null` to clear the TPRM Office.

**past\_due\_reminder\_cc\_tprm\_office** `boolean` (default: true)

Copy the TPRM Office on past-due reminders.

**past\_due\_reminder\_cc\_relationship\_owners** `boolean` (default: true)

Copy the vendor's relationship owners on past-due reminders.

**past\_due\_reminder\_cc\_requester** `boolean` (default: true)

Copy the person who requested the vendor on past-due reminders.

```bash cURL theme={null}
curl -X PUT "https://api.coverbase.app/v1/tprm-lifecycle-config" \
  -H "Authorization: Bearer ak_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "tprm_office_department_id": "cbdept_0f6c1d2e3a4b5c6d7e8f9a0b1c2d3e4f",
    "past_due_reminder_cc_requester": false
  }'
```

### Configuration object

**is\_configured** `boolean`

Whether your organization has saved a configuration.

**tprm\_office** `object | null`

The TPRM Office as `id` and `name`, or `null` when none is set.

**past\_due\_reminder\_cc\_tprm\_office** `boolean`

Whether past-due reminders copy the TPRM Office.

**past\_due\_reminder\_cc\_relationship\_owners** `boolean`

Whether past-due reminders copy the relationship owners.

**past\_due\_reminder\_cc\_requester** `boolean`

Whether past-due reminders copy the requester.

## Custom field sections

A **custom field section** groups custom fields on record pages. The `applied_to_*` flags choose which record pages show it: `applied_to_vendor`, `applied_to_service`, `applied_to_assessment`, `applied_to_control`, `applied_to_eval`, `applied_to_contract`, `applied_to_task`, `applied_to_review` and `applied_to_engagement`.

### List sections

`GET /v1/custom-field-sections` returns sections in display order.

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

Set to `true` to include archived sections.

### Create a section

`POST /v1/custom-field-sections` returns `201 Created` with the section.

**name** `string` *required*

The section name.

**description** `string`

What the section holds.

**external\_idx** `string`

Your own reference for the section.

**sort\_order** `string`

A fractional order key. The section goes last when you omit it.

**visibility\_condition** `object`

A rule that decides when the section shows.

**column\_span** `integer`

How many layout columns the section spans.

### Update a section

`PATCH /v1/custom-field-sections/{section_id}` takes the same fields. Fields you omit keep their value. To clear the visibility rule, send `visibility_condition: null`. An API key that sends `is_archived` gets `403 api_key_not_allowed`.

### Section object

**id** `string`

Section ID.

**name** `string`

Section name.

**description** `string | null`

Description.

**sort\_order** `string`

Fractional order key.

**external\_idx** `string | null`

Your reference.

**is\_archived** `boolean`

Whether the section is archived.

**applied\_to\_vendor** `boolean`

One flag per record type, as listed above.

**visibility\_condition** `object | null`

The visibility rule.

**column\_span** `integer`

Layout columns.

**created\_at** `integer`

Unix timestamp (seconds).

**updated\_at** `integer`

Unix timestamp (seconds).

## Email templates

An **email template** is a reusable email people send from Coverbase. A template with `org_wide: true` is shared with your organization. A private template belongs to whoever created it, so a template the API key creates privately is visible only to the API key.

### List templates

`GET /v1/email-templates` returns org-wide templates and the API key's own templates.

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

Set to `true` to include archived templates.

### Create a template

`POST /v1/email-templates` returns `201 Created` with the template.

**name** `string` *required*

Template name.

**subject** `string` *required*

Email subject. Template variables are allowed.

**body** `string` *required*

Email body. Template variables are allowed.

**org\_wide** `boolean` *required*

`true` shares the template with your organization.

**template\_type** `string` (default: general)

The kind of email, for example `general`, `follow_up` or `assessment_portal_invitation`.

**default\_recipients** `object`

Default `to`, `cc` and `bcc` recipients.

**ai\_instructions** `string`

Guidance Coverbase AI follows when it drafts from this template.

**reminder\_content** `object`

Reminder settings for a reminder template.

### Update a template

`PATCH /v1/email-templates/{email_template_id}` takes the same fields, all optional. Fields you omit keep their value. You can update org-wide templates and the API key's own templates. The request is refused with `422` if it contains `is_archived`. To manage attachments, use Coverbase.

## Workflow definitions

A **workflow definition** is an automation your organization built in Coverbase. To start a workflow run, see the [Workflows API](/api-reference/workflows.md).

### Get a workflow definition

`GET /v1/workflow-definitions/{workflow_definition_id}` returns the workflow: `id`, `name`, `description`, `is_enabled`, `is_archived`, `entrypoint_kind`, `definition_data` (the graph), `created_at` and `updated_at`.

### Update a workflow definition

`PATCH /v1/workflow-definitions/{workflow_definition_id}` renames a workflow, changes its description, turns it on and off, replaces its graph, or changes how it starts. Fields you omit keep their value.

**name** `string`

New name.

**description** `string | null`

New description. Send `null` to clear it.

**is\_enabled** `boolean`

`false` stops the workflow from running. `true` turns it back on.

**entrypoint\_kind** `string`

How the workflow starts. When it changes, Coverbase moves the workflow's triggers to the new kind.

**definition\_data** `object`

A replacement definition graph.

**override\_cycle\_warning** `boolean` (default: false)

Set to `true` to save a graph that would make workflows trigger each other in a loop. Without it, Coverbase returns `422 invalid_workflow_definition`.

### Versions, schedules and templates

`GET /v1/workflow-definitions/{workflow_definition_id}/versions` lists a workflow's saved versions, newest first. Each item has `id`, `version_number`, `created_by_user_id` and `created_at`. It takes `limit` (1 to 200, default 50) and `offset`.

`GET /v1/workflow-definitions/{workflow_definition_id}/schedules` lists a workflow's pending scheduled runs, soonest first. Each item has `id`, `workflow_definition_id`, `scheduled_for`, `canceled_at` and `fired_at`.

To cancel a pending scheduled run, send `POST /v1/workflow-schedules/{schedule_id}/cancel`. It returns the schedule, `404 workflow_schedule_not_found` for an unknown ID, or `409 workflow_schedule_not_pending` when the schedule already fired or was canceled.

`GET /v1/workflow-templates` lists ready-made workflows: `slug`, `name`, `description`, `category`, `audience` and `use_cases`. To copy one into your organization, send `POST /v1/workflow-templates/{template_slug}/apply` with an optional `name`. It returns `201 Created` with the new workflow, which starts turned off.

## Reminder rules

A **rule** sends a contract or document reminder. It has a `rule_name` (for example `contract_notification`), a trigger (`trigger_config` and `trigger_value`, for example `days_before_contract_end` with `{"days": [30, 60]}`), an optional condition (`condition_config` and `condition_value`), and a command (`command_config` and `command_value`, for example `send_contract_reminder` with `{"emails": ["admin@company.com"]}`).

`GET /v1/rules` lists your rules. Pass `include_archived=true` to include archived ones.

To create a rule, send `POST /v1/rules` with every field above except the optional condition. Coverbase checks each value against its configuration type and returns `422 invalid_rule` when one does not fit.

To change a rule, send `PATCH /v1/rules/{rule_id}` with the fields to change. A value applies only when you also send its configuration type, for example `trigger_value` with `trigger_config`. The request is refused with `422` if it contains `is_archived`.

## Coverbase AI agents and preferences

These endpoints return `404 not_enabled` when Coverbase Agent is not enabled for your organization.

An **agent** runs Coverbase AI playbooks on a schedule or a trigger. `GET /v1/agents` lists your agents, oldest first. Each item has `id`, `name`, `instructions`, `playbooks`, `schedule_cron`, `timezone`, `enabled`, `paused`, `created_at` and `updated_at`. The response also has `agents_paused`, which is `true` when every agent in your organization is paused.

`GET /v1/agent-templates` lists ready-made agents: `key`, `name`, `description`, `schedule_cron` and `playbooks`. `agent_id` is set when your organization already made an agent from the template. To make one, send `POST /v1/agents/from-template` with `template_key` and an optional `timezone` (default `UTC`). The new agent starts turned off.

To pause or resume every agent at once, send `PUT /v1/agents/paused` with `paused` set to `true` or `false`. The response has `agents_paused`.

To stop an agent from starting runs, send `POST /v1/agents/{agent_id}/pause`. Its live runs stop at their next turn. To let it start runs again, send `POST /v1/agents/{agent_id}/resume`. Both return the agent.

A **preference** is a standing instruction every Coverbase AI run reads. `GET /v1/agent-preferences` lists them, oldest first. Each item has `id`, `text`, `source`, `playbook`, `enabled`, `created_at` and `updated_at`.

To add a preference, send `POST /v1/agent-preferences` with `text` and an optional `playbook`. A preference without a playbook applies to every playbook. To change one, send `PATCH /v1/agent-preferences/{preference_id}` with any of `text`, `enabled` and `playbook`. Send `playbook: null` to apply it to every playbook again.

### Tool policies

`GET /v1/agent-tool-policies` lists every Coverbase AI tool that changes data. Each item has `tool`, `label`, `effect`, `policy` and `locked`. A policy is `auto` (runs without asking when a run is set to not stop), `ask` (always asks) or `off` (refused). A `locked` tool always asks.

To change policies, send `PATCH /v1/agent-tool-policies` with `policies`, an object of tool name to policy. Tools you leave out keep theirs. An unknown or locked tool returns `422 invalid_tool_policy`.

## Reports

`GET /v1/reports` lists your organization's dashboard reports, newest first. Pass `search` to match report names. Each item has `id`, `name`, `description`, `is_org_wide`, `is_default`, `created_by_user_id`, `created_at` and `updated_at`. `GET /v1/reports/{report_id}` returns one report.

To create an empty report, send `POST /v1/reports` with `name`, an optional `description` and `is_org_wide` (default `true`). To copy a report or template with copies of its charts, send `POST /v1/reports/{report_id}/clone` with an optional `name`. Both return `201 Created`.

To rename a report, change its description or make it the org default, send `PATCH /v1/reports/{report_id}` with `name`, `description` or `is_default`. The request is refused with `422` if it contains any other field. To change filters, layout or email schedules, use Coverbase.

`GET /v1/report-templates` lists dashboard templates you can clone.

## Roles

`GET /v1/roles` lists your organization's roles, built-in roles first. Each item has `id`, `key`, `name`, `description`, `system` (whether Coverbase defines the role), `archived_at` and `permissions` (the permission keys the role grants). Pass `include_archived=true` to include archived roles.

This endpoint is read only. An API key cannot create, change or assign roles. Coverbase creates your built-in roles the first time someone opens the roles page in **Settings**, so before then the list is empty.

## Organization settings

`GET /v1/org-settings` returns the settings available through the API. `PATCH /v1/org-settings` changes them, and fields you omit keep their value. The fields are `track_residual_risk`, `display_numerical_scores`, `restrict_assessment_completions`, `streamlined_assessment_creation_flow`, `enable_assessment_reviewers`, `reassessment_reminder_days`, `reassessment_collection_days`, `reassessment_review_days`, `sla_business_days`, `vendor_onboarding_reminder_days`, `vendor_onboarding_reminder_enabled`, `w9_reminder_enabled`, `w9_reminder_days_before_expiry` and `w9_expiry_years`. Any other field returns `422`. To change the organization name, sender email, status or IP allowlists, use Coverbase. Coverbase records each change in the system audit log.

## Document types

`GET /v1/document-type-settings` lists every built-in document type by group, your organization's custom types, and which types are turned off.

To turn types on or off, send `POST /v1/document-type-settings/set-enabled` with `is_enabled`, `document_types` (built-in slugs) and `custom_document_type_ids`. A type turned off leaves pickers, filters and detection, and documents already labelled keep the label. Turning off an always-on type, or sending the `custom` slug, returns `422 document_type_not_toggleable`.

`GET /v1/autofillable-fields` lists the document fields a custom field can fill itself from, with each field's custom field type, group and document types.

## Summary instructions

**Summary instructions** are named instructions Coverbase follows when it writes assessment summaries. `GET /v1/summary-instructions` lists them, and `include_archived=true` includes archived ones. Each item has `id`, `name`, `is_archived`, `latest_revision_num`, `latest_version_id` and `prompt_text`.

To add instructions, send `POST /v1/summary-instructions` with `name` and `prompt_text`. To save a new revision, send `POST /v1/summary-instructions/{prompt_id}/revisions` with `prompt_text` and the `expected_revision` you read. Coverbase returns `422` when someone saved a newer revision, and `409` while another change is in progress. Both writes need a key that belongs to an org admin.

## Workflow steps

`GET /v1/workflow-metadata` lists the building blocks for workflow steps: each action with what it reads and writes, each condition, each trigger with what it provides, and the item variables each for-each collection offers.

`GET /v1/workflow-components` lists workflow steps. Pass `workflow_definition_id` to list one workflow's steps. `GET /v1/conditions?id=...` reads the conditions steps reference; repeat `id` for each.

To add a step, send `POST /v1/workflow-components` with the workflow builder's step shape: `workflow_definition_id`, `name`, `trigger_event_types`, `parent_component_ids`, `conditions`, `condition_operator`, `action_data`, and optional `editor_position`, `color`, `watched_fields`, `draft` and `override_cycle_warning`. To change one, send `PATCH /v1/workflow-components/{component_id}` with the fields to change. Send `null` for `conditions`, `editor_position`, `color` or `watched_fields` to clear it. A step that reads supplier banking details also needs `supplier_banking:read:org`. A change that would make workflows trigger each other in a loop returns `422 invalid_workflow_component`.

## Agent setup

To create an agent, send `POST /v1/agents` with `name` and `instructions`, plus any of `playbooks`, `schedule_cron`, `timezone`, `approval_policy`, `owner_user_id` or `owner_department_id`, `enabled`, `triggers`, `daily_spend_cap_cents`, `max_runs_per_day`, `quiet_hours_start`, `quiet_hours_end` and `escalate_after_minutes`. When you name no owner, the key's user owns the agent. To change one, send `PATCH /v1/agents/{agent_id}` with the fields to change. Naming an owner person clears the owner group, and the other way round. An invalid setup returns `422 invalid_agent`.

## Report audience and charts

`GET /v1/reports/{report_id}/audience` lists the user groups a report is meant for. `PUT /v1/reports/{report_id}/audience` replaces them with `audiences`, a list of `department_id` and `is_home_default`. Naming a report a group's home dashboard moves that group's home there. Who can open the report does not change.

`PATCH /v1/reports/{report_id}` also takes `layout`, `color_theme`, `density`, `duration_unit`, `date_range`, `filter` (a vendor filter rule group) and `scheduled_export_config`. Send `null` for `filter` or `scheduled_export_config` to clear it. Setting a schedule also needs `report:export:org`. When a report is filtered to the person viewing it, every scheduled recipient must be a member of your organization, or Coverbase returns `422 invalid_report`.

`GET /v1/report-charts` lists saved charts, and `report_id` narrows it to one report. `GET /v1/report-charts/{chart_id}` returns one chart. To save a chart, send `POST /v1/report-charts` with `name`, `chart_config`, and optional `description`, `is_org_wide` and `report_id`. To change one, send `PATCH /v1/report-charts/{chart_id}`; `report_ids` replaces the full list of reports it appears on. To compute a chart's numbers without saving it, send `POST /v1/chart-statistics` with `chart_config` and an optional `time_zone`. A chart over a gated module also needs that module's read permission.

`POST /v1/program-insights` returns the TPRM program overview (KPIs, the residual risk heat grid and the pre-contract pipeline) for the level and slicers you send. It returns `404` when the TPRM lifecycle is not enabled.

## Vendor performance

A **performance rubric** scores a vendor's performance from weighted components, optionally grouped. `GET /v1/performance-rubrics` lists rubrics, default first, with their groups and components. `POST /v1/performance-rubrics` creates one with `name` and optional `description`, `questionnaire_id` and `is_default`. `PATCH /v1/performance-rubrics/{rubric_id}` changes it; send `null` to clear `description` or `questionnaire_id`.

To add a component, send `POST /v1/performance-rubrics/{rubric_id}/components` with `name` and optional `weight` (0 to 100), `evaluation_mode`, `description`, `question_id`, `ideal_answer`, `sort_order` and `group_id`. `PATCH /v1/performance-components/{component_id}` changes it. Groups work the same way through `POST /v1/performance-rubrics/{rubric_id}/groups` and `PATCH /v1/performance-groups/{group_id}`.

`GET /v1/performance-scores` lists scores, newest first, filtered by `vendor_id` or `service_id`. `POST /v1/performance-scores` records a manual score with `vendor_id`, `rubric_id`, optional `service_id`, `submitted_at` and `notes`, and `component_scores` (each `component_id`, `score` from 0 to 100, optional `value` and `notes`).

An API key cannot archive a rubric, component or group: sending `is_archived` returns `403 api_key_not_allowed`.

## Dashboard templates and exports

`GET /v1/dashboard-templates` lists ready-made dashboards and charts. To copy a dashboard into a new report, send `POST /v1/dashboard-templates/{template_slug}/apply` with an optional `name`. To add ready-made charts to a report, send `POST /v1/reports/{report_id}/chart-templates` with `template_slugs` (1 to 25).

To export a report, send `POST /v1/reports/{report_id}/exports` with `file_format` (`pdf` or `xlsx`), `export_filename` and an optional `timezone`. Coverbase returns `202 Accepted` with an export `id` and builds the file in the background. Poll `GET /v1/report-exports/{export_id}` until `status` is `complete`. The response then carries a presigned `download_url` that works for `expires_in` seconds without an `Authorization` header.

To download configured data exports as JSON, CSV or XLSX, use the existing `GET /v1/export/{slug}` and `GET /v1/export/{slug}/download` endpoints.

## Recent activity

`GET /v1/recent-activity` returns up to three items from the last week: assessments in review and newly added vendors, limited to what the key can read.

## Workflow loops and version changes

`GET /v1/workflow-definitions/{workflow_definition_id}/graph-issues` lists the loops a workflow would form with others if it were enabled. Check it before you turn a workflow on. `GET /v1/workflow-definitions/{workflow_definition_id}/versions/diff?from_version_id=...&to_version_id=...` compares two versions, step by step.

## Custom document types and AI prompts

`PATCH /v1/custom-document-types/{custom_document_type_id}` renames, regroups or redescribes one of your document types with `name`, `description` and `classification`. A new description runs the detection check again. A name another type already uses returns `409 document_type_name_taken`.

### Create a custom document type from example files

The draft, create and add-examples endpoints take `multipart/form-data`. Send each example file as its own `files` field, from 1 to 10 per request. Each file follows the same type and size limits as a vendor document upload, and a file outside them returns `400` or `413` before anything is stored.

1. `POST /v1/custom-document-types/draft` with `name` and `files` returns a suggested `description`, `classification` and `confusable_document_types`, plus `existing_document_type` when your examples already match a built-in type and `unreadable_examples` for files with no readable text. Nothing is saved.
2. `POST /v1/custom-document-types` with `name`, `description`, `classification`, up to 3 `confusable_document_types` fields and `files` creates the type, returns `201` and starts its detection check. A name another type already uses returns `409 document_type_name_taken`.
3. `POST /v1/custom-document-types/{custom_document_type_id}/examples` with `files` adds examples and runs the check again. A type holds at most 10 examples; more returns `422 too_many_examples`.

```bash theme={null}
curl -X POST "$BASE_URL/v1/custom-document-types" \
  -H "Authorization: Bearer $API_KEY" \
  -F "name=Modern Slavery Statement" \
  -F "description=Annual statement under the UK Modern Slavery Act." \
  -F "classification=esg" \
  -F "files=@statement-2024.pdf" \
  -F "files=@statement-2025.pdf"
```

The detection check can pull in vendor documents that look like your new type. Settle each one with `POST /v1/custom-document-types/{custom_document_type_id}/lookalikes/{vendor_document_id}/decision` and a `decision` of `keep`, which leaves the document's type, or `relabel`, which moves it to your type. A document the check did not pull in returns `404 lookalike_not_found`.

### AI prompts

`GET /v1/prompts/{prompt_name}/versions` lists your saved versions of one AI prompt, for example `finding_creation`, with `is_selected` on the version in use. `PUT /v1/prompts/{prompt_name}` saves a new version with `prompt_text` and an optional `prompt_key` and uses it. `POST /v1/prompts/{prompt_name}/select` uses an earlier `version_num`. The organization's assessment summary returns `409 use_summary_instructions`; manage it with the summary instructions endpoints.

`PATCH /v1/prompts/{prompt_name}/versions/{version_num}` renames a version with `name`, or archives it or brings it back with `is_archived`. When you archive the version in use, Coverbase uses `new_selected_version_num`, or your newest unarchived version when you leave it out. Archiving and unarchiving need a user key: an API key gets `403 api_key_not_allowed`. An unknown version returns `404 prompt_version_not_found`.

## Coverbase AI runs

A **run** is one instruction Coverbase AI carries out, such as "Onboard Figma for design collaboration". A run belongs to whoever started it. With an API key, that is the key, so each key sees only its own runs. Every route here returns `404 not_enabled` when Coverbase AI is off for your organization.

`GET /v1/agent-playbooks` lists the jobs Coverbase AI knows how to do. Each item has `playbook`, `title`, `description`, `steps` and an `example` instruction that starts it. `GET /v1/agent-setup` returns each setup step with `done`, the `instruction` that starts the guided setup, and `complete`.

### Start and follow a run

To start a run, send `POST /v1/agent-runs` with `instruction`. Optional fields are `mode` (`background`, the default, or `guided`) and `approval_policy` (`ask`, the default, or `auto`). Coverbase returns `201 Created` with the run. The run works in the background and stops before any change it proposes, so a person can accept or reject it. An API key cannot start a run with `approval_policy: auto`, because that run approves its own changes.

`GET /v1/agent-runs` lists your runs, newest first. Filter with `active`, `archived`, `search` and `status` (repeat it for several), and page with `limit` (1 to 50, default 20) and `offset`. `GET /v1/agent-runs/{run_id}` returns one run with its `status`, `plan`, `needs_you`, `report` and `error`.

To follow a live run, poll `GET /v1/agent-runs/{run_id}/history` with `after_sequence` set to the last `sequence` you saw. It returns the events logged since then.

To download the whole log, send `GET /v1/agent-runs/{run_id}/export` with `format` set to `json` (default) or `csv`. The response carries a presigned `download_url` that works for `expires_in` seconds (five minutes) without an `Authorization` header. The response is never cached.

### Answer and steer a run

When a run's `status` is `needs_you`, `needs_you.kind` says what it waits on. To answer, send `POST /v1/agent-runs/{run_id}/answer` with `option_key`, `text` or, for a batch, `accepted_keys`. An API key can answer a `question`. Accepting or rejecting a `checkpoint`, `batch`, `risk_review` or `failure` is a decision for a person, so an API key gets `403 api_key_not_allowed`.

To change a run's course, send `POST /v1/agent-runs/{run_id}/instruct` with `text` and an optional `idempotency_key`. A running run reads it at its next step, and a finished run continues from it. An instruction withdraws a pending proposal, so an API key cannot send one while the run waits on a decision.

`POST /v1/agent-runs/{run_id}/stop` stops a run. `POST /v1/agent-runs/{run_id}/mode` with `mode` switches a live run between `guided` and `background`. Archiving and deleting a run stay in Coverbase.

## Billing overview

`GET /v1/billing-overview` returns your billing `contracts`, each usage `metrics` entry with its limit and usage history, and `as_of`. It is read only. It returns `404 not_enabled` when billing is off for your organization. It needs `billing:read:org`, which API keys do not hold, so use a key created by a person whose role holds it.

## RFPs

These routes change an RFP and work its responses after you create it. To list, read, create, invite, publish, compare or award, use the [RFPs API](/api-reference/rfps.md). None of these routes emails a vendor.

`GET /v1/rfp-categories` lists the categories your RFPs use, so a new RFP can reuse one.

To change an RFP, send `PATCH /v1/rfp-records/{rfp_id}`. Fields you omit keep their value. Send `null` for a timeline field, `owner_id`, `service_id` or `passing_threshold` to clear it.

`POST /v1/rfp-records/{rfp_id}/pause` puts an RFP back to draft, and `POST .../cancel` cancels it. `POST .../set-status` with `status` moves it to any lifecycle status, such as `in_review` or `shortlisted`. Moving it to `archived` also needs `rfp:archive:org`, and to `awarded` needs `rfp:approve:org`. Both are decisions for a person, so an API key gets `403 api_key_not_allowed`.

`GET /v1/rfp-records/{rfp_id}/invitations` lists the invited vendors. `PATCH .../invitations/{invitation_id}` with `status` and an optional `disqualification_reason` moves one along, for example to `declined` or `disqualified`.

To record a response, send `POST /v1/rfp-records/{rfp_id}/submissions` with `invitation_id` and an optional `response_session_id`. This marks the invitation submitted. `GET .../submissions` lists responses. `POST .../submissions/rank` with `submission_ids`, best first, ranks them by hand; responses you leave out follow in their old order. `POST .../lock-rubric` with an optional `weighting_set_name` and `weights_json` freezes the scoring rubric as a new version.

## Workflow list and lifecycle requirements

`GET /v1/workflow-definitions` lists your automation workflows. Filter with `is_archived` and `is_enabled`, and page with `limit` and `offset`.

`GET /v1/lifecycle-requirements` with `target_type` (such as `vendor`) and `target_id` returns what the record still needs before each workflow-gated status change.

## Integration hub

These endpoints work the [integration hub](/user-guides/integration-hub.md): your procure-to-pay, CLM and HR connections, their syncs and the steward queue. They need the TPRM lifecycle; without it they return `404` with the code `not_enabled`. `{provider}` is a provider key such as `coupa` or `ironclad`.

`GET /v1/integrations` lists every provider offered to your organization. A connected provider carries its `connection`: `status`, `last_synced_at`, `last_sync_status`, `last_error` and its open conflict and mismatch counts. No credential is ever returned. Connecting a provider, rotating its webhook secret and disconnecting it store or delete a credential, so you do those in Coverbase.

`PUT /v1/integrations/{provider}/status` pauses or resumes a connection with `status` set to `paused` or `active`. `PUT /v1/integrations/{provider}/mappings` replaces its `field_mappings`. A provider you have not connected returns `404` with the code `connection_not_found`, and one not offered to you returns `provider_not_offered`.

`POST /v1/integrations/{provider}/syncs` starts a sync and returns `202 Accepted` with `queued`. Send an optional `object_type` to sync one kind of record. Follow it with `GET /v1/integrations/{provider}/sync-runs`, and see what each run did with every provider record in `GET /v1/integrations/{provider}/sync-records` (filter by `run_id`, `outcome` and `object_type`).

`GET /v1/integration-conflicts` is the steward queue: provider suppliers a sync could not match to one vendor, with their `candidates`. It lists open conflicts unless you pass `status`. `POST .../resolve` links a conflict to the `vendor_id` you send, and the supplier's contracts sync again. `POST .../dismiss` takes it off the queue. `POST /v1/integration-conflicts/bulk-jobs` resolves or dismisses up to 500 conflicts in the background; poll `GET /v1/integration-conflicts/bulk-jobs/{job_id}`.

`GET /v1/integration-mismatches` lists linked supplier fields whose provider value differs from Coverbase's. `POST /v1/integration-mismatches/{mismatch_id}/resolve` settles one with `choice` set to `external`, `coverbase` or `dismiss`. These two need TPRM expansion.

## Monitoring plans

These endpoints work [monitoring plans](/user-guides/monitoring-plans.md). They need the TPRM lifecycle; without it they return `404` with the code `not_enabled`.

`GET /v1/monitoring-cadence` returns the cadence matrix: for each risk tier (`levels`) and activity, the `interval_months` between runs and the `owner_role`, the reassessment interval per tier, the TPRM Office group and the plan `settings`. `PUT /v1/monitoring-cadence` replaces it with `cells`, `settings` and `tprm_office_department_id`. A cell on a risk level your scale does not have returns `422` with the code `unknown_risk_levels`. Existing plans pick up the new cadence on their next re-plan; an activity someone edited keeps its own interval. Changing the cadence needs `org_settings:update:org`, so use a key created by a person whose role holds it.

`GET /v1/monitoring-plans` lists live plans with each one's next due activity and overdue count. `GET /v1/monitoring-plans/{plan_id}` returns one plan with its `activities`, recent `events`, pending signal moves and last owner attestation. `GET /v1/engagements/{engagement_id}/monitoring-plan` and `GET /v1/services/{service_id}/monitoring-plan` find the plan for a subject; `plan` is null until it is live. `GET /v1/monitoring-plans/{plan_id}/events` returns the plan's history. `GET /v1/monitoring-activities` lists scheduled activities across plans; filter with `activity_types`, `due_window` and `mine`.

`POST .../monitoring-plan/generate` generates a plan now, or re-plans it from the cadence. A service that a live engagement covers returns `409` with the code `covered_by_engagement`, and a paused subject returns `409` with `monitoring_paused`. `PATCH /v1/monitoring-plans/{plan_id}/activities/{activity_id}` changes an activity's `interval_months`, `next_due_at`, `owner_user_id` or `is_enabled`; only the fields you send change. Generating and editing are the TPRM Office's: a caller without org-wide vendor update access gets `403` with the code `not_tprm_office`. `POST .../complete` marks a contract review or evidence request done; other activities complete from their own workflow and return `400` with the code `not_manually_completed`.

Owner attestations, IRQ refreshes, signal moves and scorecards stay in Coverbase.

## Branding

These endpoints read and change your [white-label branding](/user-guides/white-labeling.md): the logo vendors see on portals and emails, the square icon, the brand color and the vendor portal title. Changes need `org_settings:update:org`, so use a key created by a person whose role holds it.

`GET /v1/branding` returns `full_logo_url`, `icon_url`, `primary_color` and `portal_title`. The logo URLs are public.

`PATCH /v1/branding` changes `primary_color` (a 6-digit hex such as `#0052ff`) or `portal_title`, and removes the logo or icon with `remove_full_logo` or `remove_icon`. A field you omit keeps its value; `null` clears it.

`PUT /v1/branding/logo` and `PUT /v1/branding/icon` upload an image as multipart form data with `file`: PNG, JPG, SVG or WebP, up to 5 MB. Coverbase writes the resized copies vendors see. Any other file returns `422` with the code `invalid_image`. The icon is also your organization's logo at sign-in.

## Workspace logs, notes, email and settings

`GET /v1/activity-log` returns a record's activity log, newest first: field changes, creations, notes and emails. Pass `target_type` and `target_id`, and `related_activity=true` to add the activity of its related records. `GET /v1/audit-log` returns the system audit log (sign-ins, role and permission changes, settings changes, exports and API calls), filtered by time, `event_groups`, `event_types` and `search`, with the total in the `X-Total-Count` header. `GET /v1/audit-log/metadata` lists the groups and types it filters on. An API key needs the `audit:read` scope for both.

`GET /v1/notes` lists the notes on a record with their replies, and `POST /v1/notes` adds one, or a reply with `parent_id`. People a note @mentions are notified. A note on an obligation the vendor is working in a commitment portal also emails the vendor's contacts. `PATCH /v1/notes/{note_id}` replaces the `text` of a note you wrote; people it newly mentions are notified. Archiving a note stays with a signed-in user.

`GET /v1/emails` lists the emails about a record (`object_type` and `object_id`), `GET /v1/emails/search` searches them with `query`, and `GET /v1/emails/{email_id}` returns one. Each needs read access to the record the email is about: for example `vendor:read:org` for a vendor or `contract:read:org` for a contract. `POST /v1/emails` sends an email about a record from your organization's sender. It contacts the recipients: it returns `202 Accepted` with the email `status: queued`, and the email is sent in the background and shows on the record's email log.

`GET /v1/tprm-lifecycle-settings` returns which user groups the TPRM lifecycle routes work to. `GET /v1/template-variables` lists the variables a template can insert; pass exactly one of `surface` or `template_type`. `GET /v1/risk-scales/default` returns your risk scale, and `PUT /v1/risk-scales/default/levels` replaces its `levels`, with a `remap` target for each removed level records still use.

`GET /v1/home-dashboard` names the dashboard you land on at home. `POST /v1/reports/{report_id}/charts/{chart_id}/remove` takes a chart off a dashboard. `POST /v1/reports/{report_id}/scheduled-export/test` sends a dashboard's scheduled export once, to your own address only, from the draft `config` you send.

`POST /v1/performance-scores/from-response` scores a vendor against a rubric from a submitted questionnaire response; Coverbase AI reads the answers and saves the score. `GET /v1/custom-fields/usage` counts how many records hold a value for each custom field. `DELETE /v1/custom-fields/values/{value_id}` clears one value and needs a user key. `POST /v1/directory-people` adds a person who can be named on records and get their email but cannot sign in. `GET /v1/roles/{role_id}/audit-log` lists changes to a role. Creating, changing and archiving roles stays in Coverbase.

## Notifications and saved views

These routes act for the signed-in person. You only ever read or change your own settings, notifications and views. An API key has no settings, notifications or views of its own, so every route in this section gives an API key `403 api_key_not_allowed`. Use a user key.

`GET /v1/notification-settings` lists your setting for each event type and channel, with the default where you have not changed it. `POST /v1/notification-settings` turns one `event_type` on or off for one `channel` with `status`, and returns `201 Created`. `PATCH /v1/notification-settings/{setting_id}` changes a saved setting's `status`. `GET /v1/notification-settings/{setting_id}` returns one. Someone else's setting returns `404` with the code `notification_setting_not_found`. `GET /v1/notification-types` lists every event type you can configure, with its category, name and description.

`GET /v1/notification-preference` says how your email notifications arrive: `delivery_format` is `immediate` or `digest`, with `digest_hour`, `timezone` and `urgent_bypass`. `PUT /v1/notification-preference` sets all four.

`GET /v1/notifications` lists your in-app notifications, with optional `statuses`, `offset` and `limit`. `POST /v1/notifications/mark-seen` marks the `notification_ids` you send as seen. An ID that is not yours returns `404` with the code `notification_not_found`.

`GET /v1/saved-views` lists your saved views of one list, named by `object_type`, and the views shared with your organization. `POST /v1/saved-views` saves a filter, sort and search as a view you own and returns `201 Created`. `PATCH /v1/saved-views/{saved_view_id}` changes one. Only an admin changes a shared view or your organization's default view; anyone else gets `403` with the code `saved_view_not_editable`.

## Email layouts

An email layout is the frame your outgoing emails wear: one for vendors (`external`) and one for your team (`internal`).

`GET /v1/email-layouts` lists the saved layouts. `POST /v1/email-layouts` saves the layout for its `layout_type`, replacing the current one, and returns `201 Created`. `PATCH /v1/email-layouts/{layout_id}` replaces a saved layout's settings.

`GET /v1/email-layouts/{layout_id}/preview` returns the saved layout rendered as `html`, the way a real email renders it, branding included. `POST /v1/email-layouts/preview` renders a layout you have not saved: send its settings with the `logo_url` and `primary_color` filled in. Neither saves or sends anything.

`POST /v1/email-layouts/{layout_id}/dry-run` emails the saved layout's preview to you, and nobody else. It returns `202 Accepted` and the email goes out in the background. An API key has no inbox, so it gets `403` with the code `api_key_not_allowed`.

These routes need organization settings permission. A service account key does not hold it, so use a key created by a person whose role holds it.

## Create and change custom fields

`POST /v1/custom-fields` defines a custom field: `field_name`, `properties` (its `field_type` and settings), and the `applied_to_*` record types it shows on. It returns `201 Created`. A `default_value` in `properties` is filled onto the records the field applies to, and an autofilled field starts filling itself in.

`PATCH /v1/custom-fields/{custom_field_id}` changes the field's name, settings, record types or order. A field you omit keeps its value. `section_id: null` takes the field out of its section. Changing an autofilled field refills it unless you send `backfill: false`. An unknown field returns `404` with the code `custom_field_not_found`.

## Connector settings

`GET /v1/licensed-connectors` lists the licensed data connectors and whether each is configured, and `GET /v1/licensed-connectors/{connector}` returns one. `POST /v1/licensed-connectors/{connector}/test` checks that its key still works; an unconfigured connector returns `404` with the code `connector_not_configured`. These need the TPRM lifecycle.

`GET /v1/third-party-integrations/{provider}` returns a third-party integration's settings as the dashboard shows them, for `slack`, `docusign`, `dnb`, `jira`, `servicenow`, `processunity`, `valence`, `shodan`, `hibp`, `censys` or `screening`. `POST /v1/third-party-integrations/{provider}/test` checks the connection for `slack`, `servicenow`, `processunity`, `valence` and `screening`. The screening test needs `integration:update:org` and returns `ok` and `message`, so a key the provider rejects comes back as `ok: false` rather than an error. `POST /v1/third-party-integrations/slack/test-message` sends your `message` as a real Slack direct message, through your connected workspace, to the Slack account whose email matches the caller. It returns `204`. If Slack is not connected or no Slack account matches, you get `404` with the code `slack_not_found`. An API key acts as its service account, so the message lands only when that account's email matches a Slack user. `POST /v1/jira-tickets` creates a ticket in your connected Jira project. A secret never comes back, only whether it is set. Saving a key or deleting a connection stays in Coverbase.

## Errors

Most errors return a `detail` object with a `code` and a `message`. A missing permission returns `403` with `detail` set to the string `Missing required permission.`

| Status | Code | When |
| - | - | - |
| `403` | | The API key does not hold the permission the endpoint needs. |
| `404` | `status_not_found` | No status with that ID exists in your organization. |
| `422` | `invalid_status` | The status change is not allowed, for example on a system-managed status. The `message` says why. |
| `422` | `user_group_not_found` | The TPRM Office is not one of your user groups. |
| `403` | `api_key_not_allowed` | An API key tried to archive a custom field section. |
| `404` | `custom_field_section_not_found` | No section with that ID exists in your organization. |
| `404` | `email_template_not_found` | No template with that ID exists that the API key can update. |
| `404` | `workflow_definition_not_found` | No workflow with that ID exists in your organization. |
| `404` | `report_not_found` | No report with that ID exists in your organization. |
| `404` | `rule_not_found` | No rule with that ID exists in your organization. |
| `404` | `workflow_template_not_found` | No workflow template has that slug. |
| `404` | `workflow_schedule_not_found` | No schedule with that ID exists in your organization. |
| `409` | `workflow_schedule_not_pending` | The schedule already fired or was canceled. |
| `422` | `invalid_org_settings` | An organization setting has an invalid value. |
| `422` | `document_type_not_toggleable` | The type is always on, or is the generic custom slug. |
| `422` | `invalid_report` | A report filter does not compile, or a schedule recipient is not a member. |
| `404` | `user_group_not_found` | An audience names a user group that does not exist. |
| `422` | `invalid_summary_instructions` | The instructions are blank or a newer revision exists. |
| `409` | `summary_instructions_busy` | Another change to the instructions is in progress. |
| `422` | `invalid_workflow_component` | The step is not valid or would make workflows loop. |
| `404` | `workflow_component_not_found` | No step with that ID exists in your organization. |
| `422` | `invalid_chart` | The chart is not valid. |
| `404` | `chart_not_found` | No chart with that ID exists in your organization. |
| `422` | `invalid_filter` | A chart filter does not compile. |
| `422` | `invalid_performance_setup` | A rubric, component, group or score is not valid. |
| `404` | `report_export_not_found` | No report export with that ID exists. |
| `404` | `dashboard_template_not_found` | No dashboard template has that slug. |
| `404` | `chart_template_not_found` | A chart template slug does not exist. |
| `409` | `document_type_name_taken` | Another document type already has that name. |
| `409` | `use_summary_instructions` | The assessment summary is managed with summary instructions. |
| `422` | `invalid_rule` | A rule value does not fit its configuration type. |
| `422` | `invalid_agent` | The agent template cannot be used. The `message` says why. |
| `422` | `invalid_tool_policy` | A tool is unknown or locked. |
| `404` | `agent_not_found` | No agent with that ID exists in your organization. |
| `404` | `agent_preference_not_found` | No preference with that ID exists in your organization. |
| `404` | `not_enabled` | Coverbase Agent or the TPRM lifecycle is not enabled for your organization. |
| `422` | `invalid_custom_field_section` | The section change is not allowed. The `message` says why. |
| `422` | `invalid_email_template` | The template is not valid. The `message` says why. |
| `422` | `invalid_workflow_definition` | The workflow change is not allowed. The `message` says why. |
| `404` | `agent_run_not_found` | No run with that ID belongs to the caller. |
| `409` | `agent_run_conflict` | The run cannot do that in its current state. |
| `422` | `invalid_agent_run_answer` | The answer does not fit what the run waits on. |
| `403` | `api_key_not_allowed` | An API key tried to accept or reject a run's proposal, or to award or archive an RFP. |
| `404` | `rfp_not_found` | No RFP with that ID exists in your organization. |
| `404` | `rfp_invitation_not_found` | No invitation with that ID exists on the RFP. |
| `404` | `connection_not_found` | The integration provider is not connected. |
| `404` | `provider_not_offered` | The integration provider is not offered to your organization. |
| `404` | `bulk_job_not_found` | No steward bulk job with that ID exists. |
| `422` | `invalid_integration_config` | A status or field mapping is not valid. The `field` names it. |
| `404` | `plan_not_found` | No monitoring plan with that ID exists. |
| `404` | `engagement_not_found` | No engagement with that ID exists. |
| `404` | `service_not_found` | No service with that ID exists. |
| `403` | `not_tprm_office` | Only an org-wide vendor editor can change a monitoring plan. |
| `409` | `covered_by_engagement` | The service is monitored under its engagement's plan. |
| `409` | `monitoring_paused` | Monitoring is paused for the subject. |
| `422` | `unknown_risk_levels` | A cadence cell names a risk level your scale does not have. |
| `400` | `not_manually_completed` | The activity completes from its own workflow. |
| `422` | `invalid_image` | The uploaded logo or icon is not a supported image. |
| `404` | `note_not_found` | No note with that ID exists in your organization. |
| `403` | `note_not_yours` | You can edit only notes you wrote. |
| `422` | `invalid_reply` | A reply's `object_type` and `object_id` differ from its parent's. |
| `404` | `email_not_found` | No email with that ID exists in your organization. |
| `422` | `email_not_queued` | The email's record was not found, or email is off for your organization. |
| `404` | `custom_field_value_not_found` | No custom field value with that ID exists. |
| `400` | `directory_person_refused` | The person cannot be added, for example their email belongs to a member. |
| `404` | `role_not_found` | No role with that ID exists in your organization. |
| `404` | `connector_not_configured` | The licensed connector has no key. |
| `404` | `provider_not_found` | The integration is unknown or has no connection test. |
| `404` | `notification_setting_not_found` | No notification setting with that ID is yours. |
| `400` | `notification_type_retired` | The setting names a retired channel or event type. |
| `400` | `notification_channel_not_configurable` | That channel cannot be changed for that event type. |
| `400` | `invalid_preference` | The notification preference is not valid, for example an unknown `timezone`. |
| `404` | `notification_not_found` | A notification ID is not yours. |
| `404` | `saved_view_not_found` | No saved view with that ID is visible to you. |
| `403` | `saved_view_not_editable` | You cannot change that saved view. |
| `400` | `invalid_saved_view` | The saved view's filter, sort or name is not valid. The `message` says why. |
| `404` | `email_layout_not_found` | No email layout with that ID exists in your organization. |
| `404` | `custom_field_not_found` | No custom field with that ID exists in your organization. |


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