# API reference

The CalmLens REST API lets your server upload content for moderation, read decisions, organize assets and create CDN links. Each reference page lists its endpoints, describes the objects they return, and gives every endpoint a card with parameters, request and response schemas, error codes and code samples. For walkthroughs, start with the [Quick start](/docs) or a [guide](/docs/guides/uploading-assets).

## Base URLs

| Service | Base URL |
| --- | --- |
| REST API | `https://api.calmlens.com/v1` |
| CDN | `https://cdn.calmlens.com/v1` |

Request and response bodies are JSON unless an endpoint says otherwise, and timestamps are milliseconds since the Unix epoch. The full API is also available as an [OpenAPI document](/openapi.yaml?view=1).

## Authentication

Authenticate every request, except the [health check](/docs/api/system), with a project API key in the `X-Api-Key` header:

```text
X-Api-Key: your-api-key
```

Keep API keys on your server. Do not expose them in browser code or public client bundles. Each key belongs to one project and grants only the permissions you choose when you create it; see [Authentication](/docs/guides/authentication). Browsers and other untrusted clients should load private assets through [signed URLs](/docs/api/cdn).

## Conventions

- **IDs.** Resources are addressed by their UUIDs. Assets can also carry your own `externalId`, which the CDN accepts in place of the asset ID.
- **Pagination.** List endpoints take a zero-based `pageIndex` and a `pageSize` from 1 to 100, and return `items`, `total` and `hasMore`. The events feed uses a cursor instead. See [Pagination](/docs/guides/pagination-and-filtering#pagination).
- **Filtering.** The asset list accepts an RSQL-style `filter`. See [Asset filters](/docs/guides/pagination-and-filtering#asset-filters).
- **Errors.** Failed requests return an HTTP error status with a JSON body of `code`, `message` and `traceId`. Handle errors by `code`; each endpoint card lists the codes it can return. See [Error handling](/docs/guides/error-handling).
- **Request IDs.** Every response carries an `X-Request-Id` header. Include it when you contact support about a request.
- **Idempotency.** Upload and create requests accept an `Idempotency-Key` header, so a retry after a timeout returns the first response instead of creating a second asset. See [Retrying requests safely](/docs/guides/error-handling#retrying-requests-safely).
- **Rate limits.** CalmLens does not publish a general requests-per-second limit. Throttled requests return `429` with a `Retry-After` header. Upload allowances and file-size limits return their own `upload/*` errors.
- **SDKs.** The [JavaScript](/docs/sdk/javascript), [Python](/docs/sdk/python) [Go](/docs/sdk/go), [Rust](/docs/sdk/rust), [Ruby](/docs/sdk/ruby) and [Java](/docs/sdk/java) SDKs wrap these endpoints, handle authentication and uploads, and return typed errors.

## All endpoints

### Assets

| Endpoint | Description |
| --- | --- |
| [`POST /projects/:projectId/assets`](#create-asset) | Upload a new asset to a project. |
| [`POST /projects/:projectId/assets/upload`](#upload-asset-file) | Upload a file by sending its raw bytes as the request body, with the `X-CalmLens-Upload: content` header and the file's `Content-Type`. |
| [`POST /projects/:projectId/assets/multipart-upload`](#start-multipart-file-upload) | Start a multipart upload by streaming the first part's raw bytes as the request body, with the `X-CalmLens-Upload: part` header and the file's `Content-Type`. |
| [`POST /assets/:assetId/part`](#upload-asset-part) | Upload a sequential part for an in-progress asset upload. |
| [`GET /projects/:projectId/assets/page`](#get-assets-page) | Get a paginated list of assets for a project |
| [`GET /projects/:projectId/assets/search`](#search-assets) | Search accessible assets by keyword or describe an image in natural language. |
| [`GET /assets/:assetId`](#get-asset) | Get a single asset by ID |
| [`GET /assets/:assetId/children`](#get-asset-children) | Get child assets of a parent asset |
| [`POST /assets/:assetId/retry`](#retry-asset) | Process an asset that failed (status error) again. |
| [`PATCH /assets/:assetId`](#update-asset) | Update an existing asset |
| [`POST /assets/:assetId/move`](#move-asset) | Move an asset into a folder, or to the project root |
| [`DELETE /assets/:assetId/content`](#remove-asset-content) | Remove stored content, including the content derived from it in child assets, while retaining the asset records |
| [`DELETE /assets/:assetId`](#delete-asset) | Delete an asset, its child assets and their stored content from a project |
| [`POST /projects/:projectId/assets/batch`](#run-asset-batch-operation) | Queue a bounded batch operation for selected assets |

### Folders

| Endpoint | Description |
| --- | --- |
| [`GET /projects/:projectId/folders`](#list-folders) | List all asset folders in a project |
| [`POST /projects/:projectId/folders`](#create-folder) | Create an asset folder with an optional parent folder ID |
| [`GET /folders/:folderId`](#get-folder) | Get an asset folder by ID |
| [`PATCH /folders/:folderId`](#update-folder) | Rename an asset folder |
| [`DELETE /folders/:folderId`](#delete-folder) | Delete an empty asset folder by ID |
| [`POST /folders/:folderId/move`](#move-folder) | Move a folder under another folder, or to the project root |
| [`POST /assets/:assetId/move`](#move-asset) | Move an asset into a folder, or to the project root |

### Lenses

| Endpoint | Description |
| --- | --- |
| [`PUT /lenses/:lensIdentifier`](#ensure-lens) | Create a lens or update it with a version greater than the current version |
| [`PUT /projects/:projectId/lenses`](#ensure-lenses) | Create lenses or update them with their next versions |

### CDN

| Endpoint | Description |
| --- | --- |
| [`POST /assets/:assetId/signed-url`](#create-asset-signed-url) | Create a short-lived signed CDN URL for an asset |

### Events

| Endpoint | Description |
| --- | --- |
| [`GET /projects/:projectId/events`](#list-events) | List project events, oldest first, after a cursor. |

### Health check

| Endpoint | Description |
| --- | --- |
| [`GET /health-check`](#health-check) | Check whether the public API worker is responding |
