Assets

An asset is a file, remote URL, or extracted child submitted to CalmLens for classification, together with its moderation report. Use these endpoints to upload, list, update, move, retry and delete assets.

Guides: Uploading assets, Asset lifecycle, Delivering assets.

Wait for moderation or queue it

For uploads, queue=false (the HTTP default) waits for classification and returns the decision. Set queue=true to return an asset ID while moderation runs, then receive an asset.classified event through a webhook. Also handle asset.failed for processing failures.

The SDK moderate method selects queue=false; create selects queue=true. Text and images support both flows. Audio and video always run asynchronously and return pending, even with queue=false. See Uploading assets for the complete flow.

Endpoints

EndpointDescription
Upload
POST /projects/:projectId/assetsUpload a new asset to a project.
POST /projects/:projectId/assets/uploadUpload 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-uploadStart 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/partUpload a sequential part for an in-progress asset upload.
Read and review
GET /projects/:projectId/assets/pageGet a paginated list of assets for a project
GET /projects/:projectId/assets/searchSearch accessible assets by keyword or describe an image in natural language.
GET /assets/:assetIdGet a single asset by ID
GET /assets/:assetId/childrenGet child assets of a parent asset
POST /assets/:assetId/retryProcess an asset that failed (status error) again.
Organise
PATCH /assets/:assetIdUpdate an existing asset
POST /assets/:assetId/moveMove an asset into a folder, or to the project root
Remove and batch
DELETE /assets/:assetId/contentRemove stored content, including the content derived from it in child assets, while retaining the asset records
DELETE /assets/:assetIdDelete an asset, its child assets and their stored content from a project
POST /projects/:projectId/assets/batchQueue a bounded batch operation for selected assets

Endpoint details

Create Asset

Upload a new asset to a project. Direct image uploads must be smaller than 10MB. Images from 10MB through 20MB must use multipart upload; CalmLens accumulates parts and enforces the final total, and checks `totalSizeInBytes` up front when you send it. Retained multipart image originals are served through CalmLens CDN URLs. Send an `Idempotency-Key` header to retry safely without creating a second asset.

OpenAPI YAML
POST
https://api.calmlens.com/v1/projects/
/assets
import { CalmLensClient } from "@calmlens/sdk";

const client = new CalmLensClient({
  apiKey: "your-api-key",
  projectId: "your-project-id"
});

const response = await client.assets.create({
  "name": "homepage-image.jpg",
  "url": "https://example.com/image.jpg",
  "visibility": "private",
  "processingOptions": {
    "keepContentAfterProcessing": true
  }
});

Query Parameters

Edit any value to update the generated request examples.

booleanRequired
If true, queue the asset for asynchronous classification. If false, classify synchronously. Audio and video always run asynchronously and return pending. When this request starts a multipart upload, the choice is saved and applies when the final part arrives.

Request Body

Edit any value to update the generated request examples.

string (optional)Optional
Optional description of the asset
enum (optional)Optional
Visibility level of the asset
Allowed values
publicprivate
string (optional)Optional
External identifier for the asset
string (optional)Optional
External URL associated with the asset
string (optional)Optional

Response

Error Codes

401auth/missing-token
Authentication required. Send your project API key in the X-Api-Key header.
401auth/invalid-api-key
The API key is invalid, revoked or expired. Create a key under Developer → API Keys.
403auth/project-mismatch
This API key belongs to a different project. Use a key created for the project that owns this resource.
400upload/file-too-large
File size exceeds limit. Maximum direct image size is 10MB, audio/video size is 50MiB, and other files is 5GB.
400upload/image-requires-multipart-upload
Images of 10MB or more must use a multipart upload.
400upload/multipart-image-too-small
Multipart image uploads must total at least 10MB.
400upload/multipart-image-too-large
Multipart image uploads cannot exceed 20MB.
403upload/limit-exceeded
Upload limit exceeded. You have used all your free uploads. Please upgrade to Plus or Pro for unlimited uploads.
409asset/duplicate-external-id
An asset with this externalId already exists in the project.
404folder/not-found
Folder not found
400upload/invalid-mime-type
Upload file type is not supported. Uploads must use a concrete file MIME type that CalmLens can store and process, such as image/png, image/jpeg, application/pdf, or text/plain.
400upload/invalid-payload
Upload payload is invalid.
409upload/use-upload-part
Use uploadPart for multipart upload parts after the first part
400idempotency/invalid-key
The Idempotency-Key header must be 1 to 255 printable ASCII characters, such as a UUID.
409idempotency/key-reused
This Idempotency-Key was already used for a different request. Use a new key for each distinct request.
409idempotency/request-in-progress
A request with this Idempotency-Key is still being processed. Retry after the Retry-After delay to receive its result.

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`. Asset fields are query parameters. This is the upload path the SDKs use for files. Send an `Idempotency-Key` header to retry safely without creating a second asset.

OpenAPI YAML
POST
https://api.calmlens.com/v1/projects/
/assets/upload
import { readFile } from "node:fs/promises";

const response = await fetch("https://api.calmlens.com/v1/projects/:projectId/assets/upload?name=cat.jpg&contentType=image%2Fjpeg&queue=true&visibility=private", {
  method: "POST",
  headers: {
    "X-Api-Key": "your-api-key",
    "X-CalmLens-Upload": "content",
    "Content-Type": "image/jpeg",
  },
  body: await readFile("cat.jpg"),
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const data = await response.json();

Query Parameters

Edit any value to update the generated request examples.

stringRequired
Name of the asset
stringRequired
MIME type of the file, such as image/jpeg. Ambiguous types are rejected.
booleanRequired
If true, queue classification and return straight away. If false, wait for the decision. A multipart upload saves this choice and applies it when the final part arrives.
booleanRequired
Multipart uploads only: true when this is the last part
string (optional)Optional
Optional description of the asset
string (optional)Optional
Processing options as URL-encoded JSON, such as {"keepContentAfterProcessing":true}
enum (optional)Optional
Visibility of the asset
Allowed values
publicprivate
string (optional)Optional
Custom metadata as a URL-encoded JSON array of { id, value } items
string (optional)Optional
Your identifier for the asset
string (optional)Optional
URL in your app associated with the asset
string (optional)Optional
ID of the folder to upload into
number (optional)Optional
Multipart uploads only: the part number, starting at 1
number (optional)Optional
The exact size of this request's body in bytes. For a multipart upload, the size of the first part.
number (optional)Optional
Multipart uploads only: the size of the whole file in bytes, if known. CalmLens checks it against the upload limits before any part is stored, and the final part fails with upload/size-mismatch if the parts add up to a different size.

Response

Error Codes

401auth/missing-token
Authentication required. Send your project API key in the X-Api-Key header.
401auth/invalid-api-key
The API key is invalid, revoked or expired. Create a key under Developer → API Keys.
403auth/project-mismatch
This API key belongs to a different project. Use a key created for the project that owns this resource.
400upload/file-too-large
File size exceeds limit. Maximum direct image size is 10MB, audio/video size is 50MiB, and other files is 5GB.
400upload/image-requires-multipart-upload
Images of 10MB or more must use a multipart upload.
400upload/multipart-image-too-small
Multipart image uploads must total at least 10MB.
400upload/multipart-image-too-large
Multipart image uploads cannot exceed 20MB.
403upload/limit-exceeded
Upload limit exceeded. You have used all your free uploads. Please upgrade to Plus or Pro for unlimited uploads.
409asset/duplicate-external-id
An asset with this externalId already exists in the project.
404folder/not-found
Folder not found
400upload/invalid-mime-type
Upload file type is not supported. Uploads must use a concrete file MIME type that CalmLens can store and process, such as image/png, image/jpeg, application/pdf, or text/plain.
400upload/invalid-payload
Upload payload is invalid.
400idempotency/invalid-key
The Idempotency-Key header must be 1 to 255 printable ASCII characters, such as a UUID.
409idempotency/key-reused
This Idempotency-Key was already used for a different request. Use a new key for each distinct request.
409idempotency/request-in-progress
A request with this Idempotency-Key is still being processed. Retry after the Retry-After delay to receive its result.

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`. Pass `partNumber=1`, `isFinal`, the part's `sizeInBytes` and, if known, the file's `totalSizeInBytes` as query parameters, then send later parts to Upload Asset Part. The `queue` choice is saved with the upload and applies when the final part arrives.

OpenAPI YAML
POST
https://api.calmlens.com/v1/projects/
/assets/multipart-upload
const response = await fetch("https://api.calmlens.com/v1/projects/:projectId/assets/multipart-upload?name=large-video.mp4&contentType=video%2Fmp4&queue=true&partNumber=1&isFinal=false", {
  method: "POST",
  headers: {
    "X-Api-Key": "your-api-key"
  }
});

const data = await response.json();

Query Parameters

Edit any value to update the generated request examples.

stringRequired
Name of the asset
stringRequired
MIME type of the file, such as image/jpeg. Ambiguous types are rejected.
booleanRequired
If true, queue classification and return straight away. If false, wait for the decision. A multipart upload saves this choice and applies it when the final part arrives.
booleanRequired
Multipart uploads only: true when this is the last part
string (optional)Optional
Optional description of the asset
string (optional)Optional
Processing options as URL-encoded JSON, such as {"keepContentAfterProcessing":true}
enum (optional)Optional
Visibility of the asset
Allowed values
publicprivate
string (optional)Optional
Custom metadata as a URL-encoded JSON array of { id, value } items
string (optional)Optional
Your identifier for the asset
string (optional)Optional
URL in your app associated with the asset
string (optional)Optional
ID of the folder to upload into
number (optional)Optional
Multipart uploads only: the part number, starting at 1
number (optional)Optional
The exact size of this request's body in bytes. For a multipart upload, the size of the first part.
number (optional)Optional
Multipart uploads only: the size of the whole file in bytes, if known. CalmLens checks it against the upload limits before any part is stored, and the final part fails with upload/size-mismatch if the parts add up to a different size.

Response

Error Codes

401auth/missing-token
Authentication required. Send your project API key in the X-Api-Key header.
401auth/invalid-api-key
The API key is invalid, revoked or expired. Create a key under Developer → API Keys.
403auth/project-mismatch
This API key belongs to a different project. Use a key created for the project that owns this resource.
400upload/file-too-large
File size exceeds limit. Maximum direct image size is 10MB, audio/video size is 50MiB, and other files is 5GB.
400upload/image-requires-multipart-upload
Images of 10MB or more must use a multipart upload.
400upload/multipart-image-too-small
Multipart image uploads must total at least 10MB.
400upload/multipart-image-too-large
Multipart image uploads cannot exceed 20MB.
403upload/limit-exceeded
Upload limit exceeded. You have used all your free uploads. Please upgrade to Plus or Pro for unlimited uploads.
409asset/duplicate-external-id
An asset with this externalId already exists in the project.
404folder/not-found
Folder not found
400upload/invalid-mime-type
Upload file type is not supported. Uploads must use a concrete file MIME type that CalmLens can store and process, such as image/png, image/jpeg, application/pdf, or text/plain.
400upload/invalid-payload
Upload payload is invalid.
400idempotency/invalid-key
The Idempotency-Key header must be 1 to 255 printable ASCII characters, such as a UUID.
409idempotency/key-reused
This Idempotency-Key was already used for a different request. Use a new key for each distinct request.
409idempotency/request-in-progress
A request with this Idempotency-Key is still being processed. Retry after the Retry-After delay to receive its result.

Upload Asset Part

Upload a sequential part for an in-progress asset upload. Image multipart uploads must total from 10MB through 20MB; each non-final part must be at least 5MiB. The final part is classified with the `queue` choice saved when the upload started unless you pass `queue` here. To stream raw bytes instead of JSON, send the `X-CalmLens-Upload: part` header and pass `partNumber`, `isFinal` and `sizeInBytes` as query parameters.

OpenAPI YAML
POST
https://api.calmlens.com/v1/assets/
/part
import { CalmLensClient } from "@calmlens/sdk";

const client = new CalmLensClient({
  apiKey: "your-api-key",
  projectId: "your-project-id"
});

const response = await client.assets.uploadPart({
  "assetId": "987fcdeb-51a2-43d7-b890-123456789abc",
  "part": {
    "base64": "<base64-encoded-part>",
    "partNumber": 2,
    "isFinal": false
  }
});

Query Parameters

Edit any value to update the generated request examples.

boolean (optional)Optional
Overrides how the final part is classified: true queues it, false waits for the decision. When omitted, the upload uses the queue value sent when it started. Audio and video always run asynchronously and return pending.

Request Body

Edit any value to update the generated request examples.

partunionRequired

Response

Error Codes

401auth/missing-token
Authentication required. Send your project API key in the X-Api-Key header.
401auth/invalid-api-key
The API key is invalid, revoked or expired. Create a key under Developer → API Keys.
403auth/project-mismatch
This API key belongs to a different project. Use a key created for the project that owns this resource.
404asset/not-found
Asset not found
400upload/file-too-large
File size exceeds limit. Maximum direct image size is 10MB, audio/video size is 50MiB, and other files is 5GB.
400upload/multipart-image-too-small
Multipart image uploads must total at least 10MB.
400upload/multipart-image-too-large
Multipart image uploads cannot exceed 20MB.
400upload/invalid-payload
Upload payload is invalid.
409upload/not-open
Asset is not accepting additional parts
409upload/invalid-part-number
Multipart upload part number is invalid.
409upload/missing
Multipart upload state is missing
400upload/size-mismatch
The uploaded parts do not add up to the totalSizeInBytes declared when the multipart upload started.
400idempotency/invalid-key
The Idempotency-Key header must be 1 to 255 printable ASCII characters, such as a UUID.
409idempotency/key-reused
This Idempotency-Key was already used for a different request. Use a new key for each distinct request.
409idempotency/request-in-progress
A request with this Idempotency-Key is still being processed. Retry after the Retry-After delay to receive its result.

Get Assets Page

Get a paginated list of assets for a project

OpenAPI YAML
GET
https://api.calmlens.com/v1/projects/
/assets/page
import { CalmLensClient } from "@calmlens/sdk";

const client = new CalmLensClient({
  apiKey: "your-api-key",
  projectId: "your-project-id"
});

const response = await client.assets.list({
  "pageIndex": 0,
  "pageSize": 20
});

Query Parameters

Edit any value to update the generated request examples.

numberRequired
The zero-based page index
number (optional)Optional
Number of items per page (1-100)
string (optional)Optional

RSQL filter string for filtering results. See Asset filters for detailed syntax.

Examples:

  • status==rejected;parentId==null (AND conditions)
  • status==rejected,status==error (OR conditions)
  • price>100;price<500 (range filtering)
  • tags=in=(react,typescript) (array membership)

Supported operators: ==, !=, >, >=, <, <=, =in=, =out=, =like=

Logical operators: ; (AND), , (OR)

string (optional)Optional

Response

totalnumberRequired
Total number of matching items
hasMorebooleanRequired
Whether another page follows this one

Error Codes

401auth/missing-token
Authentication required. Send your project API key in the X-Api-Key header.
401auth/invalid-api-key
The API key is invalid, revoked or expired. Create a key under Developer → API Keys.
403auth/project-mismatch
This API key belongs to a different project. Use a key created for the project that owns this resource.
404project/not-found
Project not found
404folder/not-found
Folder not found

Search assets

Search accessible assets by keyword or describe an image in natural language. Semantic image search must be enabled in project settings. Results are ranked and limited to 20.

OpenAPI YAML
GET
https://api.calmlens.com/v1/projects/
/assets/search
import { CalmLensClient } from "@calmlens/sdk";

const client = new CalmLensClient({
  apiKey: "your-api-key",
  projectId: "your-project-id"
});

const response = await client.assets.search({
  "query": "a red car at night",
  "mode": "hybrid",
  "limit": 10
});

Query Parameters

Edit any value to update the generated request examples.

stringRequired
numberRequired
enumRequired
Allowed values
keywordsemantichybrid

Response

querystringRequired
semanticStatusenumRequired
Allowed values
disabledreadyindexingunavailable

Error Codes

401auth/missing-token
Authentication required. Send your project API key in the X-Api-Key header.
401auth/invalid-api-key
The API key is invalid, revoked or expired. Create a key under Developer → API Keys.
403auth/project-mismatch
This API key belongs to a different project. Use a key created for the project that owns this resource.

Get Asset

Get a single asset by ID

OpenAPI YAML
GET
https://api.calmlens.com/v1/assets/
import { CalmLensClient } from "@calmlens/sdk";

const client = new CalmLensClient({
  apiKey: "your-api-key",
  projectId: "your-project-id"
});

const response = await client.assets.retrieve({
  "assetId": "987fcdeb-51a2-43d7-b890-123456789abc"
});

Response

Error Codes

401auth/missing-token
Authentication required. Send your project API key in the X-Api-Key header.
401auth/invalid-api-key
The API key is invalid, revoked or expired. Create a key under Developer → API Keys.
403auth/project-mismatch
This API key belongs to a different project. Use a key created for the project that owns this resource.
404asset/not-found
Asset not found
404project/not-found
Project not found

Get Asset Children

Get child assets of a parent asset

OpenAPI YAML
GET
https://api.calmlens.com/v1/assets/
/children
import { CalmLensClient } from "@calmlens/sdk";

const client = new CalmLensClient({
  apiKey: "your-api-key",
  projectId: "your-project-id"
});

const response = await client.assets.listChildren({
  "pageIndex": 0,
  "pageSize": 20,
  "assetId": "987fcdeb-51a2-43d7-b890-123456789abc"
});

Query Parameters

Edit any value to update the generated request examples.

numberRequired
The zero-based page index
number (optional)Optional
Number of items per page (1-100)

Response

totalnumberRequired
Total number of matching items
hasMorebooleanRequired
Whether another page follows this one

Error Codes

401auth/missing-token
Authentication required. Send your project API key in the X-Api-Key header.
401auth/invalid-api-key
The API key is invalid, revoked or expired. Create a key under Developer → API Keys.
403auth/project-mismatch
This API key belongs to a different project. Use a key created for the project that owns this resource.

Retry Asset

Process an asset that failed (status error) again. It returns to pending and is moderated like a new upload. Its content must still be stored.

OpenAPI YAML
POST
https://api.calmlens.com/v1/assets/
/retry
import { CalmLensClient } from "@calmlens/sdk";

const client = new CalmLensClient({
  apiKey: "your-api-key",
  projectId: "your-project-id"
});

const response = await client.assets.retry({});

Response

Error Codes

401auth/missing-token
Authentication required. Send your project API key in the X-Api-Key header.
401auth/invalid-api-key
The API key is invalid, revoked or expired. Create a key under Developer → API Keys.
403auth/project-mismatch
This API key belongs to a different project. Use a key created for the project that owns this resource.
404asset/not-found
Asset not found
409asset/not-retryable
Only assets that failed to process (status error) can be retried.
409asset/content-unavailable
This asset's content is no longer stored, so it can't be processed again. Upload it again instead.
423asset/safety-held
Asset access is restricted by a safety hold.

Update Asset

Update an existing asset

OpenAPI YAML
PATCH
https://api.calmlens.com/v1/assets/
const response = await fetch("https://api.calmlens.com/v1/assets/987fcdeb-51a2-43d7-b890-123456789abc", {
  method: "PATCH",
  headers: {
    "X-Api-Key": "your-api-key",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
  "name": "Updated asset name",
  "visibility": "private"
})
});

const data = await response.json();

Request Body

Edit any value to update the generated request examples.

string (optional)Optional
Name of the asset
string (optional)Optional
Optional description of the asset
string (optional)Optional
External identifier for the asset
string (optional)Optional
External URL associated with the asset
tags[]string[]Optional
Array of tags for the asset
enum (optional)Optional
Visibility level of the asset
Allowed values
publicprivate

Response

Error Codes

401auth/missing-token
Authentication required. Send your project API key in the X-Api-Key header.
401auth/invalid-api-key
The API key is invalid, revoked or expired. Create a key under Developer → API Keys.
403auth/project-mismatch
This API key belongs to a different project. Use a key created for the project that owns this resource.
404asset/not-found
Asset not found
500asset/update-failed
Failed to update asset
409asset/duplicate-external-id
An asset with this externalId already exists in the project.

Move Asset

Move an asset into a folder, or to the project root

OpenAPI YAML
POST
https://api.calmlens.com/v1/assets/
/move
import { CalmLensClient } from "@calmlens/sdk";

const client = new CalmLensClient({
  apiKey: "your-api-key",
  projectId: "your-project-id"
});

const response = await client.assets.move({});

Request Body

Edit any value to update the generated request examples.

string (optional)Required

Response

Error Codes

401auth/missing-token
Authentication required. Send your project API key in the X-Api-Key header.
401auth/invalid-api-key
The API key is invalid, revoked or expired. Create a key under Developer → API Keys.
403auth/project-mismatch
This API key belongs to a different project. Use a key created for the project that owns this resource.
404asset/not-found
Asset not found
500asset/update-failed
Failed to update asset
423asset/safety-held
Asset access is restricted by a safety hold.
404folder/not-found
Folder not found

Remove Asset Content

Remove stored content, including the content derived from it in child assets, while retaining the asset records

OpenAPI YAML
DELETE
https://api.calmlens.com/v1/assets/
/content
import { CalmLensClient } from "@calmlens/sdk";

const client = new CalmLensClient({
  apiKey: "your-api-key",
  projectId: "your-project-id"
});

const response = await client.assets.deleteContent({
  "assetId": "987fcdeb-51a2-43d7-b890-123456789abc"
});

Response

Error Codes

401auth/missing-token
Authentication required. Send your project API key in the X-Api-Key header.
401auth/invalid-api-key
The API key is invalid, revoked or expired. Create a key under Developer → API Keys.
403auth/project-mismatch
This API key belongs to a different project. Use a key created for the project that owns this resource.
404asset/not-found
Asset not found
500asset/update-failed
Failed to update asset

Delete Asset

Delete an asset, its child assets and their stored content from a project

OpenAPI YAML
DELETE
https://api.calmlens.com/v1/assets/
import { CalmLensClient } from "@calmlens/sdk";

const client = new CalmLensClient({
  apiKey: "your-api-key",
  projectId: "your-project-id"
});

const response = await client.assets.delete({
  "assetId": "987fcdeb-51a2-43d7-b890-123456789abc"
});

Error Codes

401auth/missing-token
Authentication required. Send your project API key in the X-Api-Key header.
401auth/invalid-api-key
The API key is invalid, revoked or expired. Create a key under Developer → API Keys.
403auth/project-mismatch
This API key belongs to a different project. Use a key created for the project that owns this resource.
404asset/not-found
Asset not found

Run Asset Batch Operation

Queue a bounded batch operation for selected assets

OpenAPI YAML
POST
https://api.calmlens.com/v1/projects/
/assets/batch
const response = await fetch("https://api.calmlens.com/v1/projects/:projectId/assets/batch", {
  method: "POST",
  headers: {
    "X-Api-Key": "your-api-key",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
  "assetIds": [
    "987fcdeb-51a2-43d7-b890-123456789abc"
  ],
  "operation": "remove-content"
})
});

const data = await response.json();

Request Body

Edit any value to update the generated request examples.

assetIds[]string[]Required
enumRequired
Allowed values
deleteremove-content

Response

queuedliteralRequired

Error Codes

401auth/missing-token
Authentication required. Send your project API key in the X-Api-Key header.
401auth/invalid-api-key
The API key is invalid, revoked or expired. Create a key under Developer → API Keys.
403auth/project-mismatch
This API key belongs to a different project. Use a key created for the project that owns this resource.
404project/not-found
Project not found

The asset object

Every endpoint that returns an asset returns this object. report follows the Report format, and status moves through the asset lifecycle. Child assets that CalmLens extracts during processing, such as images in a document, are assets too: their parentId is the asset they came from, and Get Asset Children lists them.

The page object

List endpoints return a page of assets.

FieldTypePresenceDescription
pageIndexnumberRequiredThe zero-based page index. Default: 0.
pageSizenumberRequiredNumber of items per page (1-100)
orderingobject[]RequiredArray of field ordering specifications
itemsAsset[]RequiredItems on this page
totalnumberRequiredTotal number of matching items
hasMorebooleanRequiredWhether another page follows this one

Signing in

Signing out

Cookies on CalmLens

We use essential cookies to keep you signed in and the site secure. With your permission, we'll also use functional cookies to remember preferences such as your layout and documentation language, and to offer Google One Tap sign-in. We don't use analytics or advertising cookies. Manage cookies