# Policies API reference

A moderation policy decides what happens to content in each category. Policies belong to your organisation and its projects share them. Each project moderates with one policy, and an upload preset can name another for the uploads it accepts.

Every request names a project. Its API key needs `policies:read` to list and retrieve policies, and `policies:write` to create, change, delete and assign them. A key can change or delete only policies that no other project uses or owns, so it never changes how another project is moderated; change those in the portal.

Every change sends the policy's `revision`. A policy changed since you read it is refused with `policy/revision-conflict`: retrieve it again and retry.

Guide: [Moderation policies](/docs/guides/moderation-policies#manage-policies-in-code).

## Endpoints

| Endpoint                                                                                                           | Description                                                                                                                |
| ------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------- |
| [`GET /projects/:projectId/policies`](/docs/api/policies#list-policies)                                            | List the moderation policies of the project's organisation, and which one the project uses.                                |
| [`POST /projects/:projectId/policies`](/docs/api/policies#create-policy)                                           | Create a moderation policy in the project's organisation, from settings or as a copy of a built-in preset.                 |
| [`GET /projects/:projectId/policies/:policyId`](/docs/api/policies#get-policy)                                     | Get one of the organisation's moderation policies by ID                                                                    |
| [`PATCH /projects/:projectId/policies/:policyId`](/docs/api/policies#update-policy)                                | Change a policy's name, description or settings.                                                                           |
| [`POST /projects/:projectId/policies/:policyId/preset`](/docs/api/policies#reset-or-update-policy-preset)          | Reset a policy copied from a preset to its pinned preset version, or update an unchanged copy to the latest preset release |
| [`PUT /projects/:projectId/policies/:policyId/automatic-updates`](/docs/api/policies#set-policy-automatic-updates) | Switch automatic updates on or off for a project's preset policy.                                                          |
| [`DELETE /projects/:projectId/policies/:policyId`](/docs/api/policies#delete-policy)                               | Delete a policy that no project or upload preset uses.                                                                     |
| [`PUT /projects/:projectId/policy`](/docs/api/policies#assign-policy)                                              | Choose the policy the project moderates with.                                                                              |

## The policy object

| Field                  | Type                                                                                         | Presence | Description                                                                                                                   |
| ---------------------- | -------------------------------------------------------------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `id`                   | `string`                                                                                     | Required | Unique policy ID                                                                                                              |
| `name`                 | `string`                                                                                     | Required | Display name                                                                                                                  |
| `description`          | `string`                                                                                     | Required | What the policy is for                                                                                                        |
| `settings`             | `PolicySettings`                                                                             | Required | What the policy does with each category, its allowances and restrictions                                                      |
| `revision`             | `integer`                                                                                    | Required | Changes with every saved change. Send it with each change; a policy changed since is refused with `policy/revision-conflict`. |
| `automaticUpdates`     | `boolean`                                                                                    | Required | Whether the policy follows its preset: it always has the latest preset settings until its first saved edit pins a copy        |
| `preset`               | `object`                                                                                     | Nullable | Where a policy started from a built-in preset                                                                                 |
| `preset.id`            | `"general-community" \| "children-platform" \| "education-support" \| "wholesome-community"` | Required | The built-in preset the policy started from                                                                                   |
| `preset.version`       | `integer`                                                                                    | Required | The preset release the policy is pinned to. Resetting restores this version's settings.                                       |
| `preset.latestVersion` | `integer`                                                                                    | Required | The newest release of the preset. A newer one than `version` can be applied with `update`.                                    |
| `preset.projectId`     | `string`                                                                                     | Nullable | The project whose preset policy this is, or `null` for a copy. Only a project's preset policy can follow automatic updates.   |
| `projectIds`           | `string[]`                                                                                   | Required | Projects this policy moderates, as their default policy or through one of their upload presets                                |
| `createdAt`            | `integer`                                                                                    | Required | When the policy was created, in milliseconds since the Unix epoch                                                             |
| `updatedAt`            | `integer`                                                                                    | Optional | When the policy was last changed, in milliseconds since the Unix epoch                                                        |

## Endpoint details

### List Policies

List the moderation policies of the project's organisation, and which one the project uses. Policies are shared by the organisation's projects.

**Endpoint:** `GET https://api.calmlens.com/v1/projects/:projectId/policies`

**Authentication:** API Key

#### Example request

```bash
curl -X GET \
  'https://api.calmlens.com/v1/projects/proj_8fK2mQx7Lp4NvB3tRz9Y/policies' \
  -H 'X-Api-Key: your-api-key'
```

#### Response

| Field             | Type            | Required | Description                                              |
| ----------------- | --------------- | -------- | -------------------------------------------------------- |
| `policies`        | `array<Policy>` | Yes      | Every policy of the project's organisation, oldest first |
| `projectPolicyId` | `string`        | Yes      | ID of the policy the project moderates with              |

#### Error codes

| Status | Code                                                                                | Description                                                                                                                                 |
| ------ | ----------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| 401    | <a id="list-policies-error-auth-missing-token" />`auth/missing-token`               | Authentication required. Send your project API key in the X-Api-Key header.                                                                 |
| 401    | <a id="list-policies-error-auth-invalid-api-key" />`auth/invalid-api-key`           | The API key is invalid, revoked or expired. Create a key under Developer → API Keys.                                                        |
| 403    | <a id="list-policies-error-auth-project-mismatch" />`auth/project-mismatch`         | This API key belongs to a different project. Use a key created for the project that owns this resource.                                     |
| 403    | <a id="list-policies-error-auth-permission-denied" />`auth/permission-denied`       | This API key lacks a permission the request needs, such as assets:delete for an asset's folder, or the resource belongs to another project. |
| 400    | <a id="list-policies-error-validation-invalid-type" />`validation/invalid-type`     | A field has the wrong type. details.issues lists each problem.                                                                              |
| 400    | <a id="list-policies-error-validation-too-small" />`validation/too-small`           | A value is below its minimum. details.issues lists each problem.                                                                            |
| 400    | <a id="list-policies-error-validation-too-big" />`validation/too-big`               | A value is above its maximum. details.issues lists each problem.                                                                            |
| 400    | <a id="list-policies-error-validation-invalid-format" />`validation/invalid-format` | A string is not in the required format, such as an ID or URL. details.issues lists each problem.                                            |
| 400    | <a id="list-policies-error-validation-invalid-value" />`validation/invalid-value`   | A field has a value it cannot take. details.issues lists each problem.                                                                      |
| 400    | <a id="list-policies-error-validation-unknown-field" />`validation/unknown-field`   | The request has a field this endpoint does not accept.                                                                                      |
| 404    | <a id="list-policies-error-project-not-found" />`project/not-found`                 | Project not found                                                                                                                           |
| 500    | <a id="list-policies-error-misc-internal-error" />`misc/internal-error`             | An internal error occurred. Retry later, and quote requestId to support.                                                                    |

***

### Create Policy

Create a moderation policy in the project's organisation, from settings or as a copy of a built-in preset. It moderates nothing until you assign it to a project or name it on an upload preset.

**Endpoint:** `POST https://api.calmlens.com/v1/projects/:projectId/policies`

**Authentication:** API Key

#### Example request

```bash
curl -X POST \
  'https://api.calmlens.com/v1/projects/proj_8fK2mQx7Lp4NvB3tRz9Y/policies' \
  -H 'X-Api-Key: your-api-key' \
  -H "Content-Type: application/json" \
  --data '{
  "presetId": "children-platform",
  "name": "Kids section"
}'
```

#### Request body

| Field         | Type                                                                                 | Required | Description                                                                                                                   |
| ------------- | ------------------------------------------------------------------------------------ | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `name`        | `string`                                                                             | No       | Display name. Required with `settings`; a copy of a preset defaults to its name.                                              |
| `description` | `string`                                                                             | No       | What the policy is for                                                                                                        |
| `settings`    | `object`                                                                             | No       | The policy's settings, defining every category. Send this or `presetId`.                                                      |
| `presetId`    | `general-community \| children-platform \| education-support \| wholesome-community` | No       | Start from the latest release of a built-in preset instead: the copy keeps it as its reset baseline. Send this or `settings`. |

#### Response

| Field              | Type             | Required | Description                                                                                                                   |
| ------------------ | ---------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `id`               | `string`         | Yes      | Unique policy ID                                                                                                              |
| `name`             | `string`         | Yes      | Display name                                                                                                                  |
| `description`      | `string`         | Yes      | What the policy is for                                                                                                        |
| `settings`         | `PolicySettings` | Yes      | What the policy does with each category, its allowances and restrictions                                                      |
| `revision`         | `integer`        | Yes      | Changes with every saved change. Send it with each change; a policy changed since is refused with `policy/revision-conflict`. |
| `automaticUpdates` | `boolean`        | Yes      | Whether the policy follows its preset: it always has the latest preset settings until its first saved edit pins a copy        |
| `preset`           | `object \| null` | Yes      |                                                                                                                               |
| `projectIds`       | `array<string>`  | Yes      | Projects this policy moderates, as their default policy or through one of their upload presets                                |
| `createdAt`        | `integer`        | Yes      | When the policy was created, in milliseconds since the Unix epoch                                                             |
| `updatedAt`        | `integer`        | No       | When the policy was last changed, in milliseconds since the Unix epoch                                                        |

#### Error codes

| Status | Code                                                                                                    | Description                                                                                                                                 |
| ------ | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| 401    | <a id="create-policy-error-auth-missing-token" />`auth/missing-token`                                   | Authentication required. Send your project API key in the X-Api-Key header.                                                                 |
| 401    | <a id="create-policy-error-auth-invalid-api-key" />`auth/invalid-api-key`                               | The API key is invalid, revoked or expired. Create a key under Developer → API Keys.                                                        |
| 403    | <a id="create-policy-error-auth-project-mismatch" />`auth/project-mismatch`                             | This API key belongs to a different project. Use a key created for the project that owns this resource.                                     |
| 403    | <a id="create-policy-error-auth-permission-denied" />`auth/permission-denied`                           | This API key lacks a permission the request needs, such as assets:delete for an asset's folder, or the resource belongs to another project. |
| 400    | <a id="create-policy-error-validation-invalid-type" />`validation/invalid-type`                         | A field has the wrong type. details.issues lists each problem.                                                                              |
| 400    | <a id="create-policy-error-validation-too-small" />`validation/too-small`                               | A value is below its minimum. details.issues lists each problem.                                                                            |
| 400    | <a id="create-policy-error-validation-too-big" />`validation/too-big`                                   | A value is above its maximum. details.issues lists each problem.                                                                            |
| 400    | <a id="create-policy-error-validation-invalid-format" />`validation/invalid-format`                     | A string is not in the required format, such as an ID or URL. details.issues lists each problem.                                            |
| 400    | <a id="create-policy-error-validation-invalid-value" />`validation/invalid-value`                       | A field has a value it cannot take. details.issues lists each problem.                                                                      |
| 400    | <a id="create-policy-error-validation-unknown-field" />`validation/unknown-field`                       | The request has a field this endpoint does not accept.                                                                                      |
| 415    | <a id="create-policy-error-validation-unsupported-content-type" />`validation/unsupported-content-type` | Send the request body as application/json.                                                                                                  |
| 404    | <a id="create-policy-error-project-not-found" />`project/not-found`                                     | Project not found                                                                                                                           |
| 500    | <a id="create-policy-error-misc-internal-error" />`misc/internal-error`                                 | An internal error occurred. Retry later, and quote requestId to support.                                                                    |

***

### Get Policy

Get one of the organisation's moderation policies by ID

**Endpoint:** `GET https://api.calmlens.com/v1/projects/:projectId/policies/:policyId`

**Authentication:** API Key

#### Example request

```bash
curl -X GET \
  'https://api.calmlens.com/v1/projects/proj_8fK2mQx7Lp4NvB3tRz9Y/policies/pol_2Wk7Rm4Xq9Lt3Vb8Np6C' \
  -H 'X-Api-Key: your-api-key'
```

#### Response

| Field              | Type             | Required | Description                                                                                                                   |
| ------------------ | ---------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `id`               | `string`         | Yes      | Unique policy ID                                                                                                              |
| `name`             | `string`         | Yes      | Display name                                                                                                                  |
| `description`      | `string`         | Yes      | What the policy is for                                                                                                        |
| `settings`         | `PolicySettings` | Yes      | What the policy does with each category, its allowances and restrictions                                                      |
| `revision`         | `integer`        | Yes      | Changes with every saved change. Send it with each change; a policy changed since is refused with `policy/revision-conflict`. |
| `automaticUpdates` | `boolean`        | Yes      | Whether the policy follows its preset: it always has the latest preset settings until its first saved edit pins a copy        |
| `preset`           | `object \| null` | Yes      |                                                                                                                               |
| `projectIds`       | `array<string>`  | Yes      | Projects this policy moderates, as their default policy or through one of their upload presets                                |
| `createdAt`        | `integer`        | Yes      | When the policy was created, in milliseconds since the Unix epoch                                                             |
| `updatedAt`        | `integer`        | No       | When the policy was last changed, in milliseconds since the Unix epoch                                                        |

#### Error codes

| Status | Code                                                                             | Description                                                                                                                                 |
| ------ | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| 401    | <a id="get-policy-error-auth-missing-token" />`auth/missing-token`               | Authentication required. Send your project API key in the X-Api-Key header.                                                                 |
| 401    | <a id="get-policy-error-auth-invalid-api-key" />`auth/invalid-api-key`           | The API key is invalid, revoked or expired. Create a key under Developer → API Keys.                                                        |
| 403    | <a id="get-policy-error-auth-project-mismatch" />`auth/project-mismatch`         | This API key belongs to a different project. Use a key created for the project that owns this resource.                                     |
| 403    | <a id="get-policy-error-auth-permission-denied" />`auth/permission-denied`       | This API key lacks a permission the request needs, such as assets:delete for an asset's folder, or the resource belongs to another project. |
| 400    | <a id="get-policy-error-validation-invalid-type" />`validation/invalid-type`     | A field has the wrong type. details.issues lists each problem.                                                                              |
| 400    | <a id="get-policy-error-validation-too-small" />`validation/too-small`           | A value is below its minimum. details.issues lists each problem.                                                                            |
| 400    | <a id="get-policy-error-validation-too-big" />`validation/too-big`               | A value is above its maximum. details.issues lists each problem.                                                                            |
| 400    | <a id="get-policy-error-validation-invalid-format" />`validation/invalid-format` | A string is not in the required format, such as an ID or URL. details.issues lists each problem.                                            |
| 400    | <a id="get-policy-error-validation-invalid-value" />`validation/invalid-value`   | A field has a value it cannot take. details.issues lists each problem.                                                                      |
| 400    | <a id="get-policy-error-validation-unknown-field" />`validation/unknown-field`   | The request has a field this endpoint does not accept.                                                                                      |
| 404    | <a id="get-policy-error-project-not-found" />`project/not-found`                 | Project not found                                                                                                                           |
| 404    | <a id="get-policy-error-policy-not-found" />`policy/not-found`                   | Policy not found. Check the policy ID in the portal.                                                                                        |
| 500    | <a id="get-policy-error-misc-internal-error" />`misc/internal-error`             | An internal error occurred. Retry later, and quote requestId to support.                                                                    |

***

### Update Policy

Change a policy's name, description or settings. Changes apply to later moderation. Saving a policy that follows automatic updates pins it as a copy under the same ID. Only policies that no other project uses or owns can be changed through a project's key.

**Endpoint:** `PATCH https://api.calmlens.com/v1/projects/:projectId/policies/:policyId`

**Authentication:** API Key

#### Example request

```bash
curl -X PATCH \
  'https://api.calmlens.com/v1/projects/proj_8fK2mQx7Lp4NvB3tRz9Y/policies/pol_2Wk7Rm4Xq9Lt3Vb8Np6C' \
  -H 'X-Api-Key: your-api-key' \
  -H "Content-Type: application/json" \
  --data '{
  "revision": 1
}'
```

#### Request body

| Field         | Type      | Required | Description                                                                                         |
| ------------- | --------- | -------- | --------------------------------------------------------------------------------------------------- |
| `revision`    | `integer` | Yes      | The policy's current `revision`. A policy changed since is refused with `policy/revision-conflict`. |
| `name`        | `string`  | No       | Display name                                                                                        |
| `description` | `string`  | No       | What the policy is for                                                                              |
| `settings`    | `object`  | No       | The complete new settings, defining every category                                                  |

#### Response

| Field              | Type             | Required | Description                                                                                                                   |
| ------------------ | ---------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `id`               | `string`         | Yes      | Unique policy ID                                                                                                              |
| `name`             | `string`         | Yes      | Display name                                                                                                                  |
| `description`      | `string`         | Yes      | What the policy is for                                                                                                        |
| `settings`         | `PolicySettings` | Yes      | What the policy does with each category, its allowances and restrictions                                                      |
| `revision`         | `integer`        | Yes      | Changes with every saved change. Send it with each change; a policy changed since is refused with `policy/revision-conflict`. |
| `automaticUpdates` | `boolean`        | Yes      | Whether the policy follows its preset: it always has the latest preset settings until its first saved edit pins a copy        |
| `preset`           | `object \| null` | Yes      |                                                                                                                               |
| `projectIds`       | `array<string>`  | Yes      | Projects this policy moderates, as their default policy or through one of their upload presets                                |
| `createdAt`        | `integer`        | Yes      | When the policy was created, in milliseconds since the Unix epoch                                                             |
| `updatedAt`        | `integer`        | No       | When the policy was last changed, in milliseconds since the Unix epoch                                                        |

#### Error codes

| Status | Code                                                                                                    | Description                                                                                                                                 |
| ------ | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| 401    | <a id="update-policy-error-auth-missing-token" />`auth/missing-token`                                   | Authentication required. Send your project API key in the X-Api-Key header.                                                                 |
| 401    | <a id="update-policy-error-auth-invalid-api-key" />`auth/invalid-api-key`                               | The API key is invalid, revoked or expired. Create a key under Developer → API Keys.                                                        |
| 403    | <a id="update-policy-error-auth-project-mismatch" />`auth/project-mismatch`                             | This API key belongs to a different project. Use a key created for the project that owns this resource.                                     |
| 403    | <a id="update-policy-error-auth-permission-denied" />`auth/permission-denied`                           | This API key lacks a permission the request needs, such as assets:delete for an asset's folder, or the resource belongs to another project. |
| 400    | <a id="update-policy-error-validation-invalid-type" />`validation/invalid-type`                         | A field has the wrong type. details.issues lists each problem.                                                                              |
| 400    | <a id="update-policy-error-validation-too-small" />`validation/too-small`                               | A value is below its minimum. details.issues lists each problem.                                                                            |
| 400    | <a id="update-policy-error-validation-too-big" />`validation/too-big`                                   | A value is above its maximum. details.issues lists each problem.                                                                            |
| 400    | <a id="update-policy-error-validation-invalid-format" />`validation/invalid-format`                     | A string is not in the required format, such as an ID or URL. details.issues lists each problem.                                            |
| 400    | <a id="update-policy-error-validation-invalid-value" />`validation/invalid-value`                       | A field has a value it cannot take. details.issues lists each problem.                                                                      |
| 400    | <a id="update-policy-error-validation-unknown-field" />`validation/unknown-field`                       | The request has a field this endpoint does not accept.                                                                                      |
| 415    | <a id="update-policy-error-validation-unsupported-content-type" />`validation/unsupported-content-type` | Send the request body as application/json.                                                                                                  |
| 404    | <a id="update-policy-error-project-not-found" />`project/not-found`                                     | Project not found                                                                                                                           |
| 404    | <a id="update-policy-error-policy-not-found" />`policy/not-found`                                       | Policy not found. Check the policy ID in the portal.                                                                                        |
| 409    | <a id="update-policy-error-policy-revision-conflict" />`policy/revision-conflict`                       | The policy changed. Retrieve it again and retry with its current revision.                                                                  |
| 409    | <a id="update-policy-error-policy-projects-changed" />`policy/projects-changed`                         | The projects using this policy changed. Retrieve it again and review the affected projects before saving.                                   |
| 409    | <a id="update-policy-error-policy-used-by-another-project" />`policy/used-by-another-project`           | Another project uses or owns this policy, so it can only be changed from the portal or that project.                                        |
| 500    | <a id="update-policy-error-misc-internal-error" />`misc/internal-error`                                 | An internal error occurred. Retry later, and quote requestId to support.                                                                    |

***

### Reset or Update Policy Preset

Reset a policy copied from a preset to its pinned preset version, or update an unchanged copy to the latest preset release

**Endpoint:** `POST https://api.calmlens.com/v1/projects/:projectId/policies/:policyId/preset`

**Authentication:** API Key

#### Example request

```bash
curl -X POST \
  'https://api.calmlens.com/v1/projects/proj_8fK2mQx7Lp4NvB3tRz9Y/policies/pol_2Wk7Rm4Xq9Lt3Vb8Np6C/preset' \
  -H 'X-Api-Key: your-api-key' \
  -H "Content-Type: application/json" \
  --data '{
  "operation": "reset",
  "revision": 3,
  "presetVersion": 35
}'
```

#### Request body

| Field           | Type              | Required | Description                                                                                                                                                                                                          |
| --------------- | ----------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `operation`     | `reset \| update` | Yes      | `reset` restores the settings of the pinned preset version, discarding edits; `update` moves an unchanged copy to the latest preset release                                                                          |
| `revision`      | `integer`         | Yes      | The policy's current `revision`. A policy changed since is refused with `policy/revision-conflict`.                                                                                                                  |
| `presetVersion` | `integer`         | Yes      | The preset release you reviewed: the policy's `preset.version` to reset, its `preset.latestVersion` to update or switch automatic updates. A preset released since is refused with `policy/preset-version-conflict`. |

#### Response

| Field              | Type             | Required | Description                                                                                                                   |
| ------------------ | ---------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `id`               | `string`         | Yes      | Unique policy ID                                                                                                              |
| `name`             | `string`         | Yes      | Display name                                                                                                                  |
| `description`      | `string`         | Yes      | What the policy is for                                                                                                        |
| `settings`         | `PolicySettings` | Yes      | What the policy does with each category, its allowances and restrictions                                                      |
| `revision`         | `integer`        | Yes      | Changes with every saved change. Send it with each change; a policy changed since is refused with `policy/revision-conflict`. |
| `automaticUpdates` | `boolean`        | Yes      | Whether the policy follows its preset: it always has the latest preset settings until its first saved edit pins a copy        |
| `preset`           | `object \| null` | Yes      |                                                                                                                               |
| `projectIds`       | `array<string>`  | Yes      | Projects this policy moderates, as their default policy or through one of their upload presets                                |
| `createdAt`        | `integer`        | Yes      | When the policy was created, in milliseconds since the Unix epoch                                                             |
| `updatedAt`        | `integer`        | No       | When the policy was last changed, in milliseconds since the Unix epoch                                                        |

#### Error codes

| Status | Code                                                                                                          | Description                                                                                                                                 |
| ------ | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| 401    | <a id="apply-policy-preset-error-auth-missing-token" />`auth/missing-token`                                   | Authentication required. Send your project API key in the X-Api-Key header.                                                                 |
| 401    | <a id="apply-policy-preset-error-auth-invalid-api-key" />`auth/invalid-api-key`                               | The API key is invalid, revoked or expired. Create a key under Developer → API Keys.                                                        |
| 403    | <a id="apply-policy-preset-error-auth-project-mismatch" />`auth/project-mismatch`                             | This API key belongs to a different project. Use a key created for the project that owns this resource.                                     |
| 403    | <a id="apply-policy-preset-error-auth-permission-denied" />`auth/permission-denied`                           | This API key lacks a permission the request needs, such as assets:delete for an asset's folder, or the resource belongs to another project. |
| 400    | <a id="apply-policy-preset-error-validation-invalid-type" />`validation/invalid-type`                         | A field has the wrong type. details.issues lists each problem.                                                                              |
| 400    | <a id="apply-policy-preset-error-validation-too-small" />`validation/too-small`                               | A value is below its minimum. details.issues lists each problem.                                                                            |
| 400    | <a id="apply-policy-preset-error-validation-too-big" />`validation/too-big`                                   | A value is above its maximum. details.issues lists each problem.                                                                            |
| 400    | <a id="apply-policy-preset-error-validation-invalid-format" />`validation/invalid-format`                     | A string is not in the required format, such as an ID or URL. details.issues lists each problem.                                            |
| 400    | <a id="apply-policy-preset-error-validation-invalid-value" />`validation/invalid-value`                       | A field has a value it cannot take. details.issues lists each problem.                                                                      |
| 400    | <a id="apply-policy-preset-error-validation-unknown-field" />`validation/unknown-field`                       | The request has a field this endpoint does not accept.                                                                                      |
| 415    | <a id="apply-policy-preset-error-validation-unsupported-content-type" />`validation/unsupported-content-type` | Send the request body as application/json.                                                                                                  |
| 404    | <a id="apply-policy-preset-error-project-not-found" />`project/not-found`                                     | Project not found                                                                                                                           |
| 404    | <a id="apply-policy-preset-error-policy-not-found" />`policy/not-found`                                       | Policy not found. Check the policy ID in the portal.                                                                                        |
| 409    | <a id="apply-policy-preset-error-policy-revision-conflict" />`policy/revision-conflict`                       | The policy changed. Retrieve it again and retry with its current revision.                                                                  |
| 409    | <a id="apply-policy-preset-error-policy-projects-changed" />`policy/projects-changed`                         | The projects using this policy changed. Retrieve it again and review the affected projects before saving.                                   |
| 409    | <a id="apply-policy-preset-error-policy-used-by-another-project" />`policy/used-by-another-project`           | Another project uses or owns this policy, so it can only be changed from the portal or that project.                                        |
| 400    | <a id="apply-policy-preset-error-policy-no-preset" />`policy/no-preset`                                       | This policy has no preset baseline.                                                                                                         |
| 409    | <a id="apply-policy-preset-error-policy-preset-version-conflict" />`policy/preset-version-conflict`           | The preset changed. Review the latest differences and retry with its version.                                                               |
| 409    | <a id="apply-policy-preset-error-policy-preset-update-unavailable" />`policy/preset-update-unavailable`       | Only an unchanged copy of an older preset version can be updated. Reset or review your changes first.                                       |
| 500    | <a id="apply-policy-preset-error-misc-internal-error" />`misc/internal-error`                                 | An internal error occurred. Retry later, and quote requestId to support.                                                                    |

***

### Set Policy Automatic Updates

Switch automatic updates on or off for a project's preset policy. A policy that follows automatic updates always has the latest preset settings.

**Endpoint:** `PUT https://api.calmlens.com/v1/projects/:projectId/policies/:policyId/automatic-updates`

**Authentication:** API Key

#### Example request

```bash
curl -X PUT \
  'https://api.calmlens.com/v1/projects/proj_8fK2mQx7Lp4NvB3tRz9Y/policies/pol_2Wk7Rm4Xq9Lt3Vb8Np6C/automatic-updates' \
  -H 'X-Api-Key: your-api-key' \
  -H "Content-Type: application/json" \
  --data '{
  "enabled": true,
  "revision": 3,
  "presetVersion": 35
}'
```

#### Request body

| Field           | Type      | Required | Description                                                                                                                                                                                                          |
| --------------- | --------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `enabled`       | `boolean` | Yes      | `true` replaces the saved copy with a live reference to the latest preset under the same ID, discarding its changes; `false` pins the current preset version as a copy with unchanged settings                       |
| `revision`      | `integer` | Yes      | The policy's current `revision`. A policy changed since is refused with `policy/revision-conflict`.                                                                                                                  |
| `presetVersion` | `integer` | Yes      | The preset release you reviewed: the policy's `preset.version` to reset, its `preset.latestVersion` to update or switch automatic updates. A preset released since is refused with `policy/preset-version-conflict`. |

#### Response

| Field              | Type             | Required | Description                                                                                                                   |
| ------------------ | ---------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `id`               | `string`         | Yes      | Unique policy ID                                                                                                              |
| `name`             | `string`         | Yes      | Display name                                                                                                                  |
| `description`      | `string`         | Yes      | What the policy is for                                                                                                        |
| `settings`         | `PolicySettings` | Yes      | What the policy does with each category, its allowances and restrictions                                                      |
| `revision`         | `integer`        | Yes      | Changes with every saved change. Send it with each change; a policy changed since is refused with `policy/revision-conflict`. |
| `automaticUpdates` | `boolean`        | Yes      | Whether the policy follows its preset: it always has the latest preset settings until its first saved edit pins a copy        |
| `preset`           | `object \| null` | Yes      |                                                                                                                               |
| `projectIds`       | `array<string>`  | Yes      | Projects this policy moderates, as their default policy or through one of their upload presets                                |
| `createdAt`        | `integer`        | Yes      | When the policy was created, in milliseconds since the Unix epoch                                                             |
| `updatedAt`        | `integer`        | No       | When the policy was last changed, in milliseconds since the Unix epoch                                                        |

#### Error codes

| Status | Code                                                                                                                     | Description                                                                                                                                 |
| ------ | ------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
| 401    | <a id="set-policy-automatic-updates-error-auth-missing-token" />`auth/missing-token`                                     | Authentication required. Send your project API key in the X-Api-Key header.                                                                 |
| 401    | <a id="set-policy-automatic-updates-error-auth-invalid-api-key" />`auth/invalid-api-key`                                 | The API key is invalid, revoked or expired. Create a key under Developer → API Keys.                                                        |
| 403    | <a id="set-policy-automatic-updates-error-auth-project-mismatch" />`auth/project-mismatch`                               | This API key belongs to a different project. Use a key created for the project that owns this resource.                                     |
| 403    | <a id="set-policy-automatic-updates-error-auth-permission-denied" />`auth/permission-denied`                             | This API key lacks a permission the request needs, such as assets:delete for an asset's folder, or the resource belongs to another project. |
| 400    | <a id="set-policy-automatic-updates-error-validation-invalid-type" />`validation/invalid-type`                           | A field has the wrong type. details.issues lists each problem.                                                                              |
| 400    | <a id="set-policy-automatic-updates-error-validation-too-small" />`validation/too-small`                                 | A value is below its minimum. details.issues lists each problem.                                                                            |
| 400    | <a id="set-policy-automatic-updates-error-validation-too-big" />`validation/too-big`                                     | A value is above its maximum. details.issues lists each problem.                                                                            |
| 400    | <a id="set-policy-automatic-updates-error-validation-invalid-format" />`validation/invalid-format`                       | A string is not in the required format, such as an ID or URL. details.issues lists each problem.                                            |
| 400    | <a id="set-policy-automatic-updates-error-validation-invalid-value" />`validation/invalid-value`                         | A field has a value it cannot take. details.issues lists each problem.                                                                      |
| 400    | <a id="set-policy-automatic-updates-error-validation-unknown-field" />`validation/unknown-field`                         | The request has a field this endpoint does not accept.                                                                                      |
| 415    | <a id="set-policy-automatic-updates-error-validation-unsupported-content-type" />`validation/unsupported-content-type`   | Send the request body as application/json.                                                                                                  |
| 404    | <a id="set-policy-automatic-updates-error-project-not-found" />`project/not-found`                                       | Project not found                                                                                                                           |
| 404    | <a id="set-policy-automatic-updates-error-policy-not-found" />`policy/not-found`                                         | Policy not found. Check the policy ID in the portal.                                                                                        |
| 409    | <a id="set-policy-automatic-updates-error-policy-revision-conflict" />`policy/revision-conflict`                         | The policy changed. Retrieve it again and retry with its current revision.                                                                  |
| 409    | <a id="set-policy-automatic-updates-error-policy-projects-changed" />`policy/projects-changed`                           | The projects using this policy changed. Retrieve it again and review the affected projects before saving.                                   |
| 409    | <a id="set-policy-automatic-updates-error-policy-used-by-another-project" />`policy/used-by-another-project`             | Another project uses or owns this policy, so it can only be changed from the portal or that project.                                        |
| 409    | <a id="set-policy-automatic-updates-error-policy-preset-version-conflict" />`policy/preset-version-conflict`             | The preset changed. Review the latest differences and retry with its version.                                                               |
| 409    | <a id="set-policy-automatic-updates-error-policy-automatic-updates-unavailable" />`policy/automatic-updates-unavailable` | Automatic updates can only be switched on for a saved copy of a project's preset policy, and off for one that has them.                     |
| 500    | <a id="set-policy-automatic-updates-error-misc-internal-error" />`misc/internal-error`                                   | An internal error occurred. Retry later, and quote requestId to support.                                                                    |

***

### Delete Policy

Delete a policy that no project or upload preset uses. Only policies that no other project owns can be deleted through a project's key.

**Endpoint:** `DELETE https://api.calmlens.com/v1/projects/:projectId/policies/:policyId`

**Authentication:** API Key

#### Example request

```bash
curl -X DELETE \
  'https://api.calmlens.com/v1/projects/proj_8fK2mQx7Lp4NvB3tRz9Y/policies/pol_2Wk7Rm4Xq9Lt3Vb8Np6C' \
  -H 'X-Api-Key: your-api-key'
```

#### Response

```json
{
  "type": "object",
  "properties": {},
  "additionalProperties": false
}
```

#### Error codes

| Status | Code                                                                                          | Description                                                                                                                                 |
| ------ | --------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| 401    | <a id="delete-policy-error-auth-missing-token" />`auth/missing-token`                         | Authentication required. Send your project API key in the X-Api-Key header.                                                                 |
| 401    | <a id="delete-policy-error-auth-invalid-api-key" />`auth/invalid-api-key`                     | The API key is invalid, revoked or expired. Create a key under Developer → API Keys.                                                        |
| 403    | <a id="delete-policy-error-auth-project-mismatch" />`auth/project-mismatch`                   | This API key belongs to a different project. Use a key created for the project that owns this resource.                                     |
| 403    | <a id="delete-policy-error-auth-permission-denied" />`auth/permission-denied`                 | This API key lacks a permission the request needs, such as assets:delete for an asset's folder, or the resource belongs to another project. |
| 400    | <a id="delete-policy-error-validation-invalid-type" />`validation/invalid-type`               | A field has the wrong type. details.issues lists each problem.                                                                              |
| 400    | <a id="delete-policy-error-validation-too-small" />`validation/too-small`                     | A value is below its minimum. details.issues lists each problem.                                                                            |
| 400    | <a id="delete-policy-error-validation-too-big" />`validation/too-big`                         | A value is above its maximum. details.issues lists each problem.                                                                            |
| 400    | <a id="delete-policy-error-validation-invalid-format" />`validation/invalid-format`           | A string is not in the required format, such as an ID or URL. details.issues lists each problem.                                            |
| 400    | <a id="delete-policy-error-validation-invalid-value" />`validation/invalid-value`             | A field has a value it cannot take. details.issues lists each problem.                                                                      |
| 400    | <a id="delete-policy-error-validation-unknown-field" />`validation/unknown-field`             | The request has a field this endpoint does not accept.                                                                                      |
| 404    | <a id="delete-policy-error-project-not-found" />`project/not-found`                           | Project not found                                                                                                                           |
| 404    | <a id="delete-policy-error-policy-not-found" />`policy/not-found`                             | Policy not found. Check the policy ID in the portal.                                                                                        |
| 409    | <a id="delete-policy-error-policy-in-use" />`policy/in-use`                                   | Projects or upload presets still use this policy. Choose another policy for each of them before deleting it.                                |
| 409    | <a id="delete-policy-error-policy-used-by-another-project" />`policy/used-by-another-project` | Another project uses or owns this policy, so it can only be changed from the portal or that project.                                        |
| 500    | <a id="delete-policy-error-misc-internal-error" />`misc/internal-error`                       | An internal error occurred. Retry later, and quote requestId to support.                                                                    |

***

### Assign Policy

Choose the policy the project moderates with. Later uploads use it, except those through an upload preset that names its own policy.

**Endpoint:** `PUT https://api.calmlens.com/v1/projects/:projectId/policy`

**Authentication:** API Key

#### Example request

```bash
curl -X PUT \
  'https://api.calmlens.com/v1/projects/proj_8fK2mQx7Lp4NvB3tRz9Y/policy' \
  -H 'X-Api-Key: your-api-key' \
  -H "Content-Type: application/json" \
  --data '{
  "policyId": "pol_2Wk7Rm4Xq9Lt3Vb8Np6C"
}'
```

#### Request body

| Field      | Type     | Required | Description                              |
| ---------- | -------- | -------- | ---------------------------------------- |
| `policyId` | `string` | Yes      | ID of one of the organisation's policies |

#### Response

| Field              | Type             | Required | Description                                                                                                                   |
| ------------------ | ---------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `id`               | `string`         | Yes      | Unique policy ID                                                                                                              |
| `name`             | `string`         | Yes      | Display name                                                                                                                  |
| `description`      | `string`         | Yes      | What the policy is for                                                                                                        |
| `settings`         | `PolicySettings` | Yes      | What the policy does with each category, its allowances and restrictions                                                      |
| `revision`         | `integer`        | Yes      | Changes with every saved change. Send it with each change; a policy changed since is refused with `policy/revision-conflict`. |
| `automaticUpdates` | `boolean`        | Yes      | Whether the policy follows its preset: it always has the latest preset settings until its first saved edit pins a copy        |
| `preset`           | `object \| null` | Yes      |                                                                                                                               |
| `projectIds`       | `array<string>`  | Yes      | Projects this policy moderates, as their default policy or through one of their upload presets                                |
| `createdAt`        | `integer`        | Yes      | When the policy was created, in milliseconds since the Unix epoch                                                             |
| `updatedAt`        | `integer`        | No       | When the policy was last changed, in milliseconds since the Unix epoch                                                        |

#### Error codes

| Status | Code                                                                                                    | Description                                                                                                                                 |
| ------ | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| 401    | <a id="assign-policy-error-auth-missing-token" />`auth/missing-token`                                   | Authentication required. Send your project API key in the X-Api-Key header.                                                                 |
| 401    | <a id="assign-policy-error-auth-invalid-api-key" />`auth/invalid-api-key`                               | The API key is invalid, revoked or expired. Create a key under Developer → API Keys.                                                        |
| 403    | <a id="assign-policy-error-auth-project-mismatch" />`auth/project-mismatch`                             | This API key belongs to a different project. Use a key created for the project that owns this resource.                                     |
| 403    | <a id="assign-policy-error-auth-permission-denied" />`auth/permission-denied`                           | This API key lacks a permission the request needs, such as assets:delete for an asset's folder, or the resource belongs to another project. |
| 400    | <a id="assign-policy-error-validation-invalid-type" />`validation/invalid-type`                         | A field has the wrong type. details.issues lists each problem.                                                                              |
| 400    | <a id="assign-policy-error-validation-too-small" />`validation/too-small`                               | A value is below its minimum. details.issues lists each problem.                                                                            |
| 400    | <a id="assign-policy-error-validation-too-big" />`validation/too-big`                                   | A value is above its maximum. details.issues lists each problem.                                                                            |
| 400    | <a id="assign-policy-error-validation-invalid-format" />`validation/invalid-format`                     | A string is not in the required format, such as an ID or URL. details.issues lists each problem.                                            |
| 400    | <a id="assign-policy-error-validation-invalid-value" />`validation/invalid-value`                       | A field has a value it cannot take. details.issues lists each problem.                                                                      |
| 400    | <a id="assign-policy-error-validation-unknown-field" />`validation/unknown-field`                       | The request has a field this endpoint does not accept.                                                                                      |
| 415    | <a id="assign-policy-error-validation-unsupported-content-type" />`validation/unsupported-content-type` | Send the request body as application/json.                                                                                                  |
| 404    | <a id="assign-policy-error-project-not-found" />`project/not-found`                                     | Project not found                                                                                                                           |
| 404    | <a id="assign-policy-error-policy-not-found" />`policy/not-found`                                       | Policy not found. Check the policy ID in the portal.                                                                                        |
| 500    | <a id="assign-policy-error-misc-internal-error" />`misc/internal-error`                                 | An internal error occurred. Retry later, and quote requestId to support.                                                                    |
