# Hash lists API reference

Hash lists hold PDQ perceptual hashes of images a project never wants again. Image uploads are compared with every list in the project: a `flag` list records matches, and a `block` list also blocks close ones.

Guide: [Hash lists](/docs/guides/hash-lists).

## Endpoints

| Endpoint                                                                             | Description                                                             |
| ------------------------------------------------------------------------------------ | ----------------------------------------------------------------------- |
| [`GET /projects/:projectId/hash-lists`](/docs/api/hash-lists#list-hash-lists)        | List every hash list in a project                                       |
| [`POST /projects/:projectId/hash-lists`](/docs/api/hash-lists#create-hash-list)      | Create a hash list.                                                     |
| [`GET /hash-lists/:hashListId`](/docs/api/hash-lists#get-hash-list)                  | Get a hash list by ID                                                   |
| [`PATCH /hash-lists/:hashListId`](/docs/api/hash-lists#update-hash-list)             | Rename a hash list or change what its matches do.                       |
| [`DELETE /hash-lists/:hashListId`](/docs/api/hash-lists#delete-hash-list)            | Delete a hash list and every entry in it.                               |
| [`GET /hash-lists/:hashListId/entries`](/docs/api/hash-lists#list-hash-list-entries) | Get a page of the hashes in a hash list, newest first                   |
| [`POST /hash-lists/:hashListId/entries`](/docs/api/hash-lists#add-hash-list-entry)   | Add a PDQ hash to a hash list, either as a hash or from an image asset. |
| [`DELETE /hash-list-entries/:entryId`](/docs/api/hash-lists#remove-hash-list-entry)  | Remove a hash from its hash list.                                       |

## The hash list object

| Field             | Type                | Presence           | Description                                                                                                                             |
| ----------------- | ------------------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------- |
| `id`              | `string`            | Required           | Unique hash list ID                                                                                                                     |
| `projectId`       | `string`            | Required           | ID of the project that owns the list                                                                                                    |
| `name`            | `string`            | Required           | Display name                                                                                                                            |
| `description`     | `string`            | Optional, nullable | What the list is for, such as the policy it enforces                                                                                    |
| `action`          | `"flag" \| "block"` | Required           | What a match does: `flag` reports it without changing the decision, `block` blocks matches 16 bits apart or fewer and flags looser ones |
| `createdByUserId` | `string`            | Optional, nullable | ID of the user who created the list                                                                                                     |
| `createdAt`       | `integer`           | Required           | When the list was created, in milliseconds since the Unix epoch                                                                         |
| `updatedAt`       | `integer`           | Optional           | When the list was last updated, in milliseconds since the Unix epoch                                                                    |

## The hash list entry object

| Field             | Type      | Presence           | Description                                                                                                         |
| ----------------- | --------- | ------------------ | ------------------------------------------------------------------------------------------------------------------- |
| `id`              | `string`  | Required           | Unique entry ID                                                                                                     |
| `projectId`       | `string`  | Required           | ID of the project that owns the entry                                                                               |
| `hashListId`      | `string`  | Required           | ID of the list the entry belongs to                                                                                 |
| `hash`            | `string`  | Required           | PDQ hash of the listed image, as 64 hexadecimal characters                                                          |
| `quality`         | `integer` | Nullable           | PDQ quality of the hash from 0 to 100, or `null` when it was added without one. Entries below 50 are never matched. |
| `label`           | `string`  | Optional, nullable | Your own note or reference for the entry                                                                            |
| `sourceAssetId`   | `string`  | Optional, nullable | ID of the asset the hash was taken from, when it was added from an asset                                            |
| `createdByUserId` | `string`  | Optional, nullable | ID of the user who added the entry                                                                                  |
| `createdAt`       | `integer` | Required           | When the entry was added, in milliseconds since the Unix epoch                                                      |

## Endpoint details

### List Hash Lists

List every hash list in a project

**Endpoint:** `GET https://api.calmlens.com/v1/projects/:projectId/hash-lists`

**Authentication:** API Key

#### Example request

```bash
curl -X GET \
  'https://api.calmlens.com/v1/projects/123e4567-e89b-42d3-a456-426614174000/hash-lists' \
  -H 'X-Api-Key: your-api-key'
```

#### Response

| Field   | Type            | Required | Description                                  |
| ------- | --------------- | -------- | -------------------------------------------- |
| `items` | `array<object>` | Yes      | Every hash list in the project, newest first |

#### Error codes

| Status | Code                                                                         | Description                                                                                             |
| ------ | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| 401    | <a id="get-hash-lists-error-auth-missing-token" />`auth/missing-token`       | Authentication required. Send your project API key in the X-Api-Key header.                             |
| 401    | <a id="get-hash-lists-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-hash-lists-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. |
| 404    | <a id="get-hash-lists-error-project-not-found" />`project/not-found`         | Project not found                                                                                       |

***

### Create Hash List

Create a hash list. Image uploads are compared with every list in the project: a `flag` list reports matches, a `block` list also blocks close matches.

**Endpoint:** `POST https://api.calmlens.com/v1/projects/:projectId/hash-lists`

**Authentication:** API Key

#### Example request

```bash
curl -X POST \
  'https://api.calmlens.com/v1/projects/123e4567-e89b-42d3-a456-426614174000/hash-lists' \
  -H 'X-Api-Key: your-api-key' \
  -H "Content-Type: application/json" \
  --data '{
  "name": "Banned images",
  "action": "block"
}'
```

#### Request body

| Field         | Type            | Required | Description                                                                                                                             |
| ------------- | --------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `name`        | `string`        | Yes      | Display name                                                                                                                            |
| `description` | `string,null`   | No       | What the list is for, such as the policy it enforces                                                                                    |
| `action`      | `flag \| block` | Yes      | What a match does: `flag` reports it without changing the decision, `block` blocks matches 16 bits apart or fewer and flags looser ones |

#### Response

| Field             | Type              | Required | Description                                                                                                                             |
| ----------------- | ----------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `id`              | `string`          | Yes      | Unique hash list ID                                                                                                                     |
| `projectId`       | `string`          | Yes      | ID of the project that owns the list                                                                                                    |
| `name`            | `unknown`         | Yes      | Display name                                                                                                                            |
| `description`     | `unknown \| null` | No       | What the list is for, such as the policy it enforces                                                                                    |
| `action`          | `flag \| block`   | Yes      | What a match does: `flag` reports it without changing the decision, `block` blocks matches 16 bits apart or fewer and flags looser ones |
| `createdByUserId` | `string,null`     | No       | ID of the user who created the list                                                                                                     |
| `createdAt`       | `integer`         | Yes      | When the list was created, in milliseconds since the Unix epoch                                                                         |
| `updatedAt`       | `integer`         | No       | When the list was last updated, in milliseconds since the Unix epoch                                                                    |

#### Error codes

| Status | Code                                                                             | Description                                                                                             |
| ------ | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| 401    | <a id="post-hash-list-error-auth-missing-token" />`auth/missing-token`           | Authentication required. Send your project API key in the X-Api-Key header.                             |
| 401    | <a id="post-hash-list-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="post-hash-list-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. |
| 404    | <a id="post-hash-list-error-project-not-found" />`project/not-found`             | Project not found                                                                                       |
| 409    | <a id="post-hash-list-error-hash-list-limit-reached" />`hash-list/limit-reached` | This project has the most hash lists it can hold. Delete a list to add another.                         |

***

### Get Hash List

Get a hash list by ID

**Endpoint:** `GET https://api.calmlens.com/v1/hash-lists/:hashListId`

**Authentication:** API Key

#### Example request

```bash
curl -X GET \
  'https://api.calmlens.com/v1/hash-lists/123e4567-e89b-42d3-a456-426614174000' \
  -H 'X-Api-Key: your-api-key'
```

#### Response

| Field             | Type              | Required | Description                                                                                                                             |
| ----------------- | ----------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `id`              | `string`          | Yes      | Unique hash list ID                                                                                                                     |
| `projectId`       | `string`          | Yes      | ID of the project that owns the list                                                                                                    |
| `name`            | `unknown`         | Yes      | Display name                                                                                                                            |
| `description`     | `unknown \| null` | No       | What the list is for, such as the policy it enforces                                                                                    |
| `action`          | `flag \| block`   | Yes      | What a match does: `flag` reports it without changing the decision, `block` blocks matches 16 bits apart or fewer and flags looser ones |
| `createdByUserId` | `string,null`     | No       | ID of the user who created the list                                                                                                     |
| `createdAt`       | `integer`         | Yes      | When the list was created, in milliseconds since the Unix epoch                                                                         |
| `updatedAt`       | `integer`         | No       | When the list was last updated, in milliseconds since the Unix epoch                                                                    |

#### Error codes

| Status | Code                                                                        | Description                                                                                             |
| ------ | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| 401    | <a id="get-hash-list-error-auth-missing-token" />`auth/missing-token`       | Authentication required. Send your project API key in the X-Api-Key header.                             |
| 401    | <a id="get-hash-list-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-hash-list-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. |
| 404    | <a id="get-hash-list-error-hash-list-not-found" />`hash-list/not-found`     | Hash list not found. Check the list ID in the portal.                                                   |

***

### Update Hash List

Rename a hash list or change what its matches do. The new action applies to later uploads.

**Endpoint:** `PATCH https://api.calmlens.com/v1/hash-lists/:hashListId`

**Authentication:** API Key

#### Example request

```bash
curl -X PATCH \
  'https://api.calmlens.com/v1/hash-lists/123e4567-e89b-42d3-a456-426614174000' \
  -H 'X-Api-Key: your-api-key' \
  -H "Content-Type: application/json" \
  --data '{
  "name": "Removed images"
}'
```

#### Request body

| Field         | Type            | Required | Description                                                                                                                             |
| ------------- | --------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `name`        | `string`        | No       | Display name                                                                                                                            |
| `description` | `string,null`   | No       | What the list is for, such as the policy it enforces                                                                                    |
| `action`      | `flag \| block` | No       | What a match does: `flag` reports it without changing the decision, `block` blocks matches 16 bits apart or fewer and flags looser ones |

#### Response

| Field             | Type              | Required | Description                                                                                                                             |
| ----------------- | ----------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `id`              | `string`          | Yes      | Unique hash list ID                                                                                                                     |
| `projectId`       | `string`          | Yes      | ID of the project that owns the list                                                                                                    |
| `name`            | `unknown`         | Yes      | Display name                                                                                                                            |
| `description`     | `unknown \| null` | No       | What the list is for, such as the policy it enforces                                                                                    |
| `action`          | `flag \| block`   | Yes      | What a match does: `flag` reports it without changing the decision, `block` blocks matches 16 bits apart or fewer and flags looser ones |
| `createdByUserId` | `string,null`     | No       | ID of the user who created the list                                                                                                     |
| `createdAt`       | `integer`         | Yes      | When the list was created, in milliseconds since the Unix epoch                                                                         |
| `updatedAt`       | `integer`         | No       | When the list was last updated, in milliseconds since the Unix epoch                                                                    |

#### Error codes

| Status | Code                                                                          | Description                                                                                             |
| ------ | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| 401    | <a id="patch-hash-list-error-auth-missing-token" />`auth/missing-token`       | Authentication required. Send your project API key in the X-Api-Key header.                             |
| 401    | <a id="patch-hash-list-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="patch-hash-list-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. |
| 404    | <a id="patch-hash-list-error-hash-list-not-found" />`hash-list/not-found`     | Hash list not found. Check the list ID in the portal.                                                   |

***

### Delete Hash List

Delete a hash list and every entry in it. Later uploads are no longer compared with it.

**Endpoint:** `DELETE https://api.calmlens.com/v1/hash-lists/:hashListId`

**Authentication:** API Key

#### Example request

```bash
curl -X DELETE \
  'https://api.calmlens.com/v1/hash-lists/123e4567-e89b-42d3-a456-426614174000' \
  -H 'X-Api-Key: your-api-key'
```

#### Response

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

#### Error codes

| Status | Code                                                                           | Description                                                                                             |
| ------ | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------- |
| 401    | <a id="delete-hash-list-error-auth-missing-token" />`auth/missing-token`       | Authentication required. Send your project API key in the X-Api-Key header.                             |
| 401    | <a id="delete-hash-list-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-hash-list-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. |
| 404    | <a id="delete-hash-list-error-hash-list-not-found" />`hash-list/not-found`     | Hash list not found. Check the list ID in the portal.                                                   |

***

### List Hash List Entries

Get a page of the hashes in a hash list, newest first

**Endpoint:** `GET https://api.calmlens.com/v1/hash-lists/:hashListId/entries`

**Authentication:** API Key

#### Example request

```bash
curl -X GET \
  'https://api.calmlens.com/v1/hash-lists/123e4567-e89b-42d3-a456-426614174000/entries?pageSize=50' \
  -H 'X-Api-Key: your-api-key'
```

#### Query parameters

| Field      | Type            | Required | Description                                             |
| ---------- | --------------- | -------- | ------------------------------------------------------- |
| `cursor`   | `string`        | No       | The previous page’s nextCursor; omit for the first page |
| `pageSize` | `integer`       | No       |                                                         |
| `ordering` | `array<object>` | No       |                                                         |

#### Response

| Field        | Type            | Required | Description                                                      |
| ------------ | --------------- | -------- | ---------------------------------------------------------------- |
| `items`      | `array<object>` | Yes      |                                                                  |
| `nextCursor` | `string,null`   | Yes      | Pass as cursor for the next page; null when no more items remain |
| `pageSize`   | `integer`       | Yes      |                                                                  |
| `hasMore`    | `boolean`       | Yes      |                                                                  |
| `ordering`   | `array<object>` | Yes      |                                                                  |

#### Error codes

| Status | Code                                                                                        | Description                                                                                             |
| ------ | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| 401    | <a id="get-hash-list-entries-error-auth-missing-token" />`auth/missing-token`               | Authentication required. Send your project API key in the X-Api-Key header.                             |
| 401    | <a id="get-hash-list-entries-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-hash-list-entries-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. |
| 400    | <a id="get-hash-list-entries-error-validation-invalid-cursor" />`validation/invalid-cursor` | The cursor is invalid or belongs to a different query.                                                  |
| 404    | <a id="get-hash-list-entries-error-hash-list-not-found" />`hash-list/not-found`             | Hash list not found. Check the list ID in the portal.                                                   |

***

### Add Hash List Entry

Add a PDQ hash to a hash list, either as a hash or from an image asset. Adding a hash the list already holds returns the existing entry.

**Endpoint:** `POST https://api.calmlens.com/v1/hash-lists/:hashListId/entries`

**Authentication:** API Key

#### Example request

```bash
curl -X POST \
  'https://api.calmlens.com/v1/hash-lists/123e4567-e89b-42d3-a456-426614174000/entries' \
  -H 'X-Api-Key: your-api-key' \
  -H "Content-Type: application/json" \
  --data '{
  "assetId": "8f7d2c1e-4b3a-4c5d-9e8f-1a2b3c4d5e6f",
  "label": "Reported spam"
}'
```

#### Request body

| Field     | Type              | Required | Description                                                                           |
| --------- | ----------------- | -------- | ------------------------------------------------------------------------------------- |
| `hash`    | `string`          | No       | A PDQ hash to add, as 64 hexadecimal characters. Send this or `assetId`.              |
| `quality` | `integer \| null` | No       | PDQ quality of `hash`, from 0 to 100. Hashes below 50 are never matched.              |
| `assetId` | `string`          | No       | An image asset in the same project whose perceptual hash to add. Send this or `hash`. |
| `label`   | `string,null`     | No       | Your own note or reference for the entry                                              |

#### Response

| Field             | Type              | Required | Description                                                                                                         |
| ----------------- | ----------------- | -------- | ------------------------------------------------------------------------------------------------------------------- |
| `id`              | `string`          | Yes      | Unique entry ID                                                                                                     |
| `projectId`       | `string`          | Yes      | ID of the project that owns the entry                                                                               |
| `hashListId`      | `string`          | Yes      | ID of the list the entry belongs to                                                                                 |
| `hash`            | `string`          | Yes      | PDQ hash of the listed image, as 64 hexadecimal characters                                                          |
| `quality`         | `integer \| null` | Yes      | PDQ quality of the hash from 0 to 100, or `null` when it was added without one. Entries below 50 are never matched. |
| `label`           | `unknown \| null` | No       | Your own note or reference for the entry                                                                            |
| `sourceAssetId`   | `string \| null`  | No       | ID of the asset the hash was taken from, when it was added from an asset                                            |
| `createdByUserId` | `string,null`     | No       | ID of the user who added the entry                                                                                  |
| `createdAt`       | `integer`         | Yes      | When the entry was added, in milliseconds since the Unix epoch                                                      |

#### Error codes

| Status | Code                                                                                               | Description                                                                                             |
| ------ | -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| 401    | <a id="post-hash-list-entry-error-auth-missing-token" />`auth/missing-token`                       | Authentication required. Send your project API key in the X-Api-Key header.                             |
| 401    | <a id="post-hash-list-entry-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="post-hash-list-entry-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. |
| 404    | <a id="post-hash-list-entry-error-hash-list-not-found" />`hash-list/not-found`                     | Hash list not found. Check the list ID in the portal.                                                   |
| 404    | <a id="post-hash-list-entry-error-asset-not-found" />`asset/not-found`                             | Asset not found                                                                                         |
| 409    | <a id="post-hash-list-entry-error-hash-list-asset-not-hashed" />`hash-list/asset-not-hashed`       | This asset has no perceptual hash. Only image assets that finished processing can be added.             |
| 409    | <a id="post-hash-list-entry-error-hash-list-entry-limit-reached" />`hash-list/entry-limit-reached` | This project's hash lists hold the most entries they can. Remove entries to add more.                   |

***

### Remove Hash List Entry

Remove a hash from its hash list. Later uploads no longer match it.

**Endpoint:** `DELETE https://api.calmlens.com/v1/hash-list-entries/:entryId`

**Authentication:** API Key

#### Example request

```bash
curl -X DELETE \
  'https://api.calmlens.com/v1/hash-list-entries/123e4567-e89b-42d3-a456-426614174000' \
  -H 'X-Api-Key: your-api-key'
```

#### Response

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

#### Error codes

| Status | Code                                                                                         | Description                                                                                             |
| ------ | -------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| 401    | <a id="delete-hash-list-entry-error-auth-missing-token" />`auth/missing-token`               | Authentication required. Send your project API key in the X-Api-Key header.                             |
| 401    | <a id="delete-hash-list-entry-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-hash-list-entry-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. |
| 404    | <a id="delete-hash-list-entry-error-hash-list-entry-not-found" />`hash-list/entry-not-found` | Hash list entry not found.                                                                              |
