# Closare API

Version: 0.7.0

Auto-generated OpenAPI definition for all enabled modules.

## Servers
- https://demo-carrier.closare.com/api – Default environment

## DELETE `/api_keys/keys`

Delete API key

Removes an API key by identifier. The key must belong to the current tenant and fall within the requester organization scope.

**Tags:** API Keys

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | query | any | Required. API key identifier to delete |

### Responses

**200** – Key deleted successfully

Content-Type: `application/json`

```json
{
  "success": true
}
```

**400** – Missing or invalid identifier

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Organization outside allowed scope

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Key not found within scope

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/api_keys/keys?id=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/api_keys/keys`

List API keys

Returns paginated API keys visible to the current user, including per-key role assignments and organization context.

**Tags:** API Keys

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |

### Responses

**200** – Collection of API keys

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "name": "string",
      "description": null,
      "keyPrefix": "string",
      "organizationId": null,
      "organizationName": null,
      "createdAt": "string",
      "lastUsedAt": null,
      "expiresAt": null,
      "roles": [
        {
          "id": "string",
          "name": null
        }
      ]
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

**400** – Tenant context missing

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Forbidden by organization scope

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/api_keys/keys" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/api_keys/keys`

Create API key

Creates a new API key, returning the one-time secret value together with the generated key prefix and scope details.

**Tags:** API Keys

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "name": "string",
  "description": null,
  "tenantId": null,
  "organizationId": null,
  "roles": [],
  "expiresAt": null
}
```

### Responses

**201** – API key created successfully

Content-Type: `application/json`

```json
{
  "id": "string",
  "name": "string",
  "keyPrefix": "string",
  "tenantId": null,
  "organizationId": null,
  "roles": [
    {
      "id": "string",
      "name": null
    }
  ]
}
```

**400** – Invalid payload or missing tenant context

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Organization outside allowed scope

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/api_keys/keys" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"name\": \"string\",
  \"description\": null,
  \"tenantId\": null,
  \"organizationId\": null,
  \"roles\": [],
  \"expiresAt\": null
}"
```

## DELETE `/attachments`

Delete attachment

Removes an uploaded attachment and deletes the stored asset.

**Tags:** Attachments

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | query | any | Required |

### Responses

**200** – Attachment deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Missing attachment identifier

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Attachment not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/attachments?id=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/attachments`

List attachments for a record

Returns uploaded attachments for the given entity record, ordered by newest first.

**Tags:** Attachments

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| entityId | query | any | Required. Entity identifier that owns the attachments |
| recordId | query | any | Required. Record identifier within the entity |
| page | query | any | Optional |
| pageSize | query | any | Optional |

### Responses

**200** – Attachments found for the record

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "url": "string",
      "fileName": "string",
      "fileSize": 1,
      "createdAt": "string",
      "mimeType": null,
      "content": null
    }
  ]
}
```

**400** – Missing entity or record identifiers

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/attachments?entityId=string&recordId=string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/attachments`

Upload attachment

Uploads a new attachment using multipart form-data and stores metadata for later retrieval.

**Tags:** Attachments

**Requires authentication.**

### Request Body

Content-Type: `multipart/form-data`

```text
entityId=string
recordId=string
file=string
```

### Responses

**200** – Attachment stored successfully

Content-Type: `application/json`

```json
{
  "ok": true,
  "item": {
    "id": "string",
    "url": "string",
    "fileName": "string",
    "fileSize": 1,
    "content": null
  }
}
```

**400** – Payload validation error

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Attachment violates field constraints

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/attachments" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: multipart/form-data" \
  -d "{
  \"entityId\": \"string\",
  \"recordId\": \"string\",
  \"file\": \"string\"
}"
```

## GET `/attachments/file/{id}`

Download or serve attachment file

Returns the raw file content for an attachment. Path parameter: {id} - Attachment UUID. Query parameter: ?download=1 - Force file download with Content-Disposition header. Access control is enforced based on partition settings.

**Tags:** Attachments

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – File content with appropriate MIME type

Content-Type: `application/json`

**400** – Missing attachment ID

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized - authentication required for private partitions

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Forbidden - insufficient permissions

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Attachment or file not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Partition misconfigured

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/attachments/file/:id" \
  -H "Accept: application/json"
```

## GET `/attachments/image/{id}/{slug}`

Serve image with optional resizing

Returns an image attachment with optional on-the-fly resizing and cropping. Resized images are cached for performance. Only works with image MIME types. Path parameter: {id} - Attachment UUID. Query parameters: ?width=N (1-4000 pixels), ?height=N (1-4000 pixels), ?cropType=cover|contain (resize behavior).

**Tags:** Attachments

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| slug | path | any | Optional |

### Responses

**200** – Binary image content (Content-Type: image/jpeg, image/png, etc.)

Content-Type: `application/json`

**400** – Invalid parameters, missing ID, or non-image attachment

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized - authentication required for private partitions

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Forbidden - insufficient permissions

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Image not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Partition misconfigured or image rendering failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/attachments/image/:id/:slug" \
  -H "Accept: application/json"
```

## GET `/attachments/library`

List attachments

Returns paginated list of attachments with optional filtering by search term, partition, and tags. Includes available tags and partitions.

**Tags:** Attachments

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional. Page number for pagination |
| pageSize | query | any | Optional. Number of items per page (max 100) |
| search | query | any | Optional. Search by file name (case-insensitive) |
| partition | query | any | Optional. Filter by partition code |
| tags | query | any | Optional. Filter by tags (comma-separated) |
| sortField | query | any | Optional. Field to sort by |
| sortDir | query | any | Optional. Sort direction |

### Responses

**200** – Attachments list with pagination and metadata

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "fileName": "string",
      "fileSize": 1,
      "mimeType": "string",
      "partitionCode": "string",
      "partitionTitle": null,
      "url": null,
      "createdAt": "string",
      "tags": [
        "string"
      ],
      "assignments": [],
      "content": null
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1,
  "availableTags": [
    "string"
  ],
  "partitions": [
    {
      "code": "string",
      "title": "string",
      "description": null,
      "isPublic": true
    }
  ]
}
```

**400** – Invalid query parameters

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/attachments/library?page=1&pageSize=25" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/attachments/library/{id}`

Delete attachment

Permanently deletes an attachment file from storage and database. Emits CRUD side effects.

**Tags:** Attachments

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Attachment deleted successfully

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Invalid attachment ID

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Attachment not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/attachments/library/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/attachments/library/{id}`

Get attachment details

Returns complete details of an attachment including metadata, tags, assignments, and custom fields.

**Tags:** Attachments

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Attachment details

Content-Type: `application/json`

```json
{
  "item": {
    "id": "00000000-0000-4000-8000-000000000000",
    "fileName": "string",
    "fileSize": 1,
    "mimeType": "string",
    "partitionCode": "string",
    "partitionTitle": null,
    "tags": [
      "string"
    ],
    "assignments": [],
    "content": null,
    "customFields": null
  }
}
```

**400** – Invalid attachment ID

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Attachment not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/attachments/library/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PATCH `/attachments/library/{id}`

Update attachment metadata

Updates attachment tags, assignments, and custom fields. Emits CRUD side effects for indexing and events.

**Tags:** Attachments

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Attachment updated successfully

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Invalid payload or attachment ID

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Attachment not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to save attributes

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PATCH "https://demo-carrier.closare.com/api/attachments/library/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## DELETE `/attachments/partitions`

Delete partition

Deletes a partition. Default partitions cannot be deleted. Partitions with existing attachments cannot be deleted.

**Tags:** Attachments

**Requires authentication.**

### Responses

**200** – Partition deleted successfully

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Invalid ID or default partition deletion attempt

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Partitions locked in demo mode

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Partition not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**409** – Partition in use

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/attachments/partitions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/attachments/partitions`

List all attachment partitions

Returns all configured attachment partitions with storage settings, OCR configuration, and access control settings.

**Tags:** Attachments

**Requires authentication.**

### Responses

**200** – List of partitions

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "code": "string",
      "title": "string",
      "description": null,
      "isPublic": true,
      "requiresOcr": true,
      "ocrModel": null,
      "configJson": null,
      "createdAt": null,
      "updatedAt": null,
      "envKey": "string"
    }
  ]
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/attachments/partitions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/attachments/partitions`

Create new partition

Creates a new attachment partition with specified storage and OCR settings. Requires unique partition code.

**Tags:** Attachments

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "code": "string",
  "title": "string",
  "description": null,
  "ocrModel": null,
  "storageDriver": "local",
  "configJson": null
}
```

### Responses

**201** – Partition created successfully

Content-Type: `application/json`

```json
{
  "item": {
    "id": "00000000-0000-4000-8000-000000000000",
    "code": "string",
    "title": "string",
    "description": null,
    "isPublic": true,
    "requiresOcr": true,
    "ocrModel": null,
    "configJson": null,
    "createdAt": null,
    "updatedAt": null,
    "envKey": "string"
  }
}
```

**400** – Invalid payload or partition code

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Partitions locked in demo mode

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**409** – Partition code already exists

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/attachments/partitions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"code\": \"string\",
  \"title\": \"string\",
  \"description\": null,
  \"ocrModel\": null,
  \"storageDriver\": \"local\",
  \"configJson\": null
}"
```

## PUT `/attachments/partitions`

Update partition

Updates an existing partition. Partition code cannot be changed. Title, description, OCR settings, and access control can be modified.

**Tags:** Attachments

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "code": "string",
  "title": "string",
  "description": null,
  "ocrModel": null,
  "storageDriver": "local",
  "configJson": null,
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Partition updated successfully

Content-Type: `application/json`

```json
{
  "item": {
    "id": "00000000-0000-4000-8000-000000000000",
    "code": "string",
    "title": "string",
    "description": null,
    "isPublic": true,
    "requiresOcr": true,
    "ocrModel": null,
    "configJson": null,
    "createdAt": null,
    "updatedAt": null,
    "envKey": "string"
  }
}
```

**400** – Invalid payload or code change attempt

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Partitions locked in demo mode

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Partition not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/attachments/partitions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"code\": \"string\",
  \"title\": \"string\",
  \"description\": null,
  \"ocrModel\": null,
  \"storageDriver\": \"local\",
  \"configJson\": null,
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## POST `/attachments/transfer`

Transfer attachments to different record

Transfers one or more attachments from one record to another within the same entity type. Updates attachment assignments and metadata to reflect the new record.

**Tags:** Attachments

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "entityId": "string",
  "attachmentIds": [
    "00000000-0000-4000-8000-000000000000"
  ],
  "toRecordId": "string"
}
```

### Responses

**200** – Attachments transferred successfully

Content-Type: `application/json`

```json
{
  "ok": true,
  "updated": 1
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Attachments not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Attachment model missing

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/attachments/transfer" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityId\": \"string\",
  \"attachmentIds\": [
    \"00000000-0000-4000-8000-000000000000\"
  ],
  \"toRecordId\": \"string\"
}"
```

## GET `/audit_logs/audit-logs/access`

Retrieve access logs

Fetches paginated access audit logs scoped to the authenticated user. Tenant administrators can optionally expand the search to other actors or organizations.

**Tags:** Audit & Action Logs

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| organizationId | query | any | Optional. Limit results to a specific organization |
| actorUserId | query | any | Optional. Filter by actor user id (tenant administrators only) |
| resourceKind | query | any | Optional. Restrict to a resource kind such as `order` or `product` |
| accessType | query | any | Optional. Access type filter, e.g. `read` or `export` |
| page | query | any | Optional. Page number (default 1) |
| pageSize | query | any | Optional. Page size (default 50) |
| limit | query | any | Optional. Explicit maximum number of records when paginating manually |
| before | query | any | Optional. Return logs created before this ISO-8601 timestamp |
| after | query | any | Optional. Return logs created after this ISO-8601 timestamp |

### Responses

**200** – Access logs returned successfully

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "resourceKind": "string",
      "resourceId": "string",
      "accessType": "string",
      "actorUserId": null,
      "actorUserName": null,
      "tenantId": null,
      "tenantName": null,
      "organizationId": null,
      "organizationName": null,
      "fields": [
        "string"
      ],
      "context": null,
      "createdAt": "string"
    }
  ],
  "canViewTenant": true,
  "page": 1,
  "pageSize": 1,
  "total": 1,
  "totalPages": 1
}
```

**400** – Invalid filters supplied

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Caller has no resolved tenant scope and is not a superadmin

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/audit_logs/audit-logs/access" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/audit_logs/audit-logs/actions`

Fetch action logs

Returns recent action audit log entries. Tenant administrators can widen the scope to other actors or organizations, and callers can optionally restrict results to undoable actions.

**Tags:** Audit & Action Logs

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| organizationId | query | any | Optional. Limit results to a specific organization |
| actorUserId | query | any | Optional. Filter logs created by specific actor IDs (tenant administrators only). Accepts a single UUID or a comma-separated UUID list. |
| resourceKind | query | any | Optional. Filter by resource kind (e.g., "order", "product") |
| resourceId | query | any | Optional. Filter by resource ID (UUID of the specific record) |
| actionType | query | any | Optional. Filter by action type (`create`, `edit`, `delete`, `assign`). Accepts a single value or a comma-separated list. |
| fieldName | query | any | Optional. Filter to entries where the given field changed. Accepts a single field name or a comma-separated list. |
| includeRelated | query | any | Optional. When `true`, also returns changes to child entities linked via parentResourceKind/parentResourceId |
| includeTotal | query | any | Optional. When `true`, the response includes the filtered total count. |
| undoableOnly | query | any | Optional. When `true`, only undoable actions are returned |
| limit | query | any | Optional. Maximum number of records to return (default 50, max 1000) |
| offset | query | any | Optional. Zero-based record offset for pagination (legacy — prefer page/pageSize) |
| page | query | any | Optional. Page number (default 1) |
| pageSize | query | any | Optional. Page size (default 50, max 200) |
| sortField | query | any | Optional. Sort field: `createdAt`, `user`, `action`, `field`, or `source`. |
| sortDir | query | any | Optional. Sort direction: `asc` or `desc`. |
| before | query | any | Optional. Return actions created before this ISO-8601 timestamp |
| after | query | any | Optional. Return actions created after this ISO-8601 timestamp |

### Responses

**200** – Action logs retrieved successfully

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "commandId": "string",
      "actionLabel": null,
      "executionState": "done",
      "actorUserId": null,
      "actorUserName": null,
      "tenantId": null,
      "tenantName": null,
      "organizationId": null,
      "organizationName": null,
      "resourceKind": null,
      "resourceId": null,
      "parentResourceKind": null,
      "parentResourceId": null,
      "undoToken": null,
      "createdAt": "string",
      "updatedAt": "string",
      "snapshotBefore": null,
      "snapshotAfter": null,
      "changes": null,
      "context": null
    }
  ],
  "canViewTenant": true,
  "page": 1,
  "pageSize": 1,
  "total": 1,
  "totalPages": 1
}
```

**400** – Invalid filter values

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Caller has no resolved tenant scope and is not a superadmin

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/audit_logs/audit-logs/actions?includeRelated=false&includeTotal=false&undoableOnly=false" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/audit_logs/audit-logs/actions/export`

Export action logs as CSV

Returns a CSV attachment containing filtered action audit log entries. Tenant administrators can widen the scope to other actors or organizations.

**Tags:** Audit & Action Logs

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| organizationId | query | any | Optional. Limit results to a specific organization |
| actorUserId | query | any | Optional. Filter logs created by specific actor IDs (tenant administrators only). Accepts a single UUID or a comma-separated UUID list. |
| resourceKind | query | any | Optional. Filter by resource kind (e.g., "order", "product") |
| resourceId | query | any | Optional. Filter by resource ID (UUID of the specific record) |
| actionType | query | any | Optional. Filter by action type (`create`, `edit`, `delete`, `assign`). Accepts a single value or a comma-separated list. |
| fieldName | query | any | Optional. Filter to entries where the given field changed. Accepts a single field name or a comma-separated list. |
| includeRelated | query | any | Optional. When `true`, also returns changes to child entities linked via parentResourceKind/parentResourceId |
| undoableOnly | query | any | Optional. When `true`, only undoable actions are returned |
| limit | query | any | Optional. Maximum number of records to export (default 1000, capped at 1000) |
| sortField | query | any | Optional. Sort field: `createdAt`, `user`, `action`, `field`, or `source`. |
| sortDir | query | any | Optional. Sort direction: `asc` or `desc`. |
| before | query | any | Optional. Return actions created before this ISO-8601 timestamp |
| after | query | any | Optional. Return actions created after this ISO-8601 timestamp |

### Responses

**200** – CSV export generated successfully

Content-Type: `application/json`

```json
{
  "file": "csv"
}
```

**400** – Invalid filter values

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Caller has no resolved tenant scope and is not a superadmin

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/audit_logs/audit-logs/actions/export?includeRelated=false&undoableOnly=false" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/audit_logs/audit-logs/actions/redo`

Redo by action log id

Redoes the latest undone command owned by the caller. Requires the action to still be eligible for redo within tenant and organization scope.

**Tags:** Audit & Action Logs

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "logId": "string"
}
```

### Responses

**200** – Redo executed successfully

Content-Type: `application/json`

```json
{
  "ok": true,
  "logId": null,
  "undoToken": null
}
```

**400** – Log not eligible for redo

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Redo blocked by scope checks

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/audit_logs/audit-logs/actions/redo" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"logId\": \"string\"
}"
```

## POST `/audit_logs/audit-logs/actions/undo`

Undo action by token

Replays the undo handler registered for a command. The provided undo token must match the latest undoable log entry accessible to the caller.

**Tags:** Audit & Action Logs

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "undoToken": "string"
}
```

### Responses

**200** – Undo applied successfully

Content-Type: `application/json`

```json
{
  "ok": true,
  "logId": "string"
}
```

**400** – Invalid or unavailable undo token

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Undo blocked by organization or tenant scope

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**422** – Undo deliberately blocked by a beforeUndo command interceptor. The interceptor chooses the status (any 4xx/5xx) and may replace the body.

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/audit_logs/audit-logs/actions/undo" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"undoToken\": \"string\"
}"
```

## GET `/auth/admin/nav`

Resolve backend chrome bootstrap payload

Returns the backend chrome payload available to the authenticated administrator after applying scope, RBAC, role defaults, and personal sidebar preferences.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Responses

**200** – Backend chrome payload

Content-Type: `application/json`

```json
{
  "brand": null,
  "groups": [
    {
      "name": "string",
      "items": [
        {
          "href": "string",
          "title": "string"
        }
      ]
    }
  ],
  "settingsSections": [
    {
      "id": "string",
      "label": "string",
      "items": [
        {
          "id": "string",
          "label": "string",
          "href": "string"
        }
      ]
    }
  ],
  "settingsPathPrefixes": [
    "string"
  ],
  "profileSections": [
    {
      "id": "string",
      "label": "string",
      "items": [
        {
          "id": "string",
          "label": "string",
          "href": "string"
        }
      ]
    }
  ],
  "profilePathPrefixes": [
    "string"
  ],
  "grantedFeatures": [
    "string"
  ],
  "roles": [
    "string"
  ],
  "currentOrganization": null
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/auth/admin/nav" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/auth/autologin`

Auto sign-in using env-configured demo credentials

When OM_AUTOLOGIN_EMAIL / OM_AUTOLOGIN_PASSWORD are configured, signs the visitor in with those credentials and redirects into the app. Intended for single-tenant demo instances only. Falls back to the login page when disabled or misconfigured.

**Tags:** Authentication & Accounts

### Responses

**200** – Success response

Content-Type: `application/json`

**307** – Redirect into the app (or to /login on failure)

Content-Type: `text/html`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/auth/autologin" \
  -H "Accept: application/json"
```

## POST `/auth/feature-check`

Check feature grants for the current user

Evaluates which of the requested features are available to the signed-in user within the active tenant / organization context.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "features": [
    "string"
  ]
}
```

### Responses

**200** – Evaluation result

Content-Type: `application/json`

```json
{
  "ok": true,
  "granted": [
    "string"
  ],
  "userId": "string"
}
```

**400** – Invalid request — features array missing, too large, or contains invalid entries

Content-Type: `application/json`

```json
{
  "ok": false,
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "ok": false,
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/auth/feature-check" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"features\": [
    \"string\"
  ]
}"
```

## GET `/auth/features`

List declared feature flags

Returns all static features contributed by the enabled modules along with their module source.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Responses

**200** – Aggregated feature catalog

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "title": "string",
      "module": "string"
    }
  ],
  "modules": [
    {
      "id": "string",
      "title": "string"
    }
  ]
}
```

**401** – Missing authentication

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/auth/features" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/auth/locale`

Set locale and redirect

Stores the selected locale in a cookie and redirects to a safe local path.

**Tags:** Authentication & Accounts

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| locale | query | any | Required |
| redirect | query | any | Optional |

### Responses

**200** – Success response

Content-Type: `application/json`

**302** – Locale cookie set and request redirected

Content-Type: `application/json`

**400** – Invalid locale

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/auth/locale?locale=en" \
  -H "Accept: application/json"
```

## POST `/auth/locale`

Set locale

Stores the selected locale in a cookie and returns a JSON success response.

**Tags:** Authentication & Accounts

### Request Body

Content-Type: `application/json`

```json
{
  "locale": "en"
}
```

### Responses

**200** – Locale cookie set

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Invalid locale or malformed request body

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/auth/locale" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"locale\": \"en\"
}"
```

## POST `/auth/login`

Authenticate user credentials

Validates the submitted credentials and issues a bearer token cookie for subsequent API calls.

**Tags:** Authentication & Accounts

### Request Body

Content-Type: `application/x-www-form-urlencoded`

```text
email=user%40example.com&password=string
```

### Responses

**200** – Authentication succeeded

Content-Type: `application/json`

```json
{
  "ok": true,
  "token": "string",
  "redirect": null
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "ok": false,
  "error": "string"
}
```

**401** – Invalid credentials

Content-Type: `application/json`

```json
{
  "ok": false,
  "error": "string"
}
```

**403** – User lacks required role

Content-Type: `application/json`

```json
{
  "ok": false,
  "error": "string"
}
```

**429** – Too many login attempts

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/auth/login" \
  -H "Accept: application/json" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "email=user%40example.com&password=string"
```

## POST `/auth/logout`

Invalidate session and redirect

Clears authentication cookies and redirects the browser to the login page.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Responses

**201** – Success response

Content-Type: `application/json`

**302** – Redirect to login after successful logout

Content-Type: `text/html`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/auth/logout" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/auth/profile`

Get current profile

Returns the email address, display name, and roles for the signed-in user. The display name is null when unset.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Responses

**200** – Profile payload

Content-Type: `application/json`

```json
{
  "email": "user@example.com",
  "name": null,
  "roles": [
    "string"
  ]
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – User not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/auth/profile" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/auth/profile`

Update current profile

Updates the email address or password for the signed-in user.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Profile updated

Content-Type: `application/json`

```json
{
  "ok": true,
  "email": "user@example.com"
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/auth/profile" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## POST `/auth/reset`

Send reset email

Requests a password reset email for the given account. The endpoint always returns `ok: true` to avoid leaking account existence.

**Tags:** Authentication & Accounts

### Request Body

Content-Type: `application/x-www-form-urlencoded`

```text
email=user%40example.com
```

### Responses

**200** – Reset email dispatched (or ignored for unknown accounts)

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Invalid request origin

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**429** – Too many password reset requests

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Password reset email origin is not configured

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/auth/reset" \
  -H "Accept: application/json" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "email=user%40example.com"
```

## POST `/auth/reset/confirm`

Complete password reset

Validates the reset token and updates the user password.

**Tags:** Authentication & Accounts

### Request Body

Content-Type: `application/x-www-form-urlencoded`

```text
token=string&password=string
```

### Responses

**200** – Password reset succeeded

Content-Type: `application/json`

```json
{
  "ok": true,
  "redirect": "string"
}
```

**400** – Invalid token or payload

Content-Type: `application/json`

```json
{
  "ok": false,
  "error": "string"
}
```

**429** – Too many reset confirmation attempts

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/auth/reset/confirm" \
  -H "Accept: application/json" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "token=string&password=string"
```

## DELETE `/auth/roles`

Delete role

Deletes a role by identifier. Fails when users remain assigned.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | query | any | Required. Role identifier |

### Responses

**200** – Role deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Role cannot be deleted

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Role not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/auth/roles?id=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/auth/roles`

List roles

Returns available roles within the current tenant. Super administrators receive visibility across tenants.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | query | any | Optional |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| tenantId | query | any | Optional |

### Responses

**200** – Role collection

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "usersCount": 1,
      "tenantId": null,
      "tenantName": null,
      "updatedAt": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/auth/roles?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/auth/roles`

Create role

Creates a new role anchored to the caller's tenant. Non-superadmins cannot target another tenant; supplying a foreign `tenantId` is rejected.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "name": "string"
}
```

### Responses

**201** – Role created

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/auth/roles" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"name\": \"string\"
}"
```

## PUT `/auth/roles`

Update role

Updates mutable fields on an existing role.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Role updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Role not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/auth/roles" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/auth/roles/acl`

Fetch role ACL

Returns the feature and organization assignments associated with a role within the current tenant.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| roleId | query | any | Required |
| tenantId | query | any | Optional |

### Responses

**200** – Role ACL entry

Content-Type: `application/json`

```json
{
  "isSuperAdmin": true,
  "features": [
    "string"
  ],
  "organizations": null,
  "updatedAt": null
}
```

**400** – Invalid role id

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Role not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/auth/roles/acl?roleId=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/auth/roles/acl`

Update role ACL

Replaces the feature list, super admin flag, and optional organization assignments for a role.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "roleId": "00000000-0000-4000-8000-000000000000",
  "organizations": null
}
```

### Responses

**200** – Role ACL updated

Content-Type: `application/json`

```json
{
  "ok": true,
  "sanitized": true
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Insufficient privileges to modify ACL

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Role not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/auth/roles/acl" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"roleId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizations\": null
}"
```

## GET `/auth/session/refresh`

Refresh auth cookie from session token (browser)

Exchanges an existing `session_token` cookie for a fresh JWT auth cookie and redirects the browser.

**Tags:** Authentication & Accounts

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| redirect | query | any | Optional. Absolute or relative URL to redirect after refresh |

### Responses

**200** – Success response

Content-Type: `application/json`

**302** – Redirect to target location when session is valid

Content-Type: `text/html`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/auth/session/refresh" \
  -H "Accept: application/json"
```

## POST `/auth/session/refresh`

Refresh access token (API/mobile)

Exchanges a refresh token for a new JWT access token. Pass the refresh token obtained from login in the request body.

**Tags:** Authentication & Accounts

### Request Body

Content-Type: `application/json`

```json
{
  "refreshToken": "string"
}
```

### Responses

**200** – New access token issued

Content-Type: `application/json`

```json
{
  "ok": true,
  "accessToken": "string",
  "expiresIn": 1
}
```

**400** – Missing refresh token

Content-Type: `application/json`

```json
{
  "ok": false,
  "error": "string"
}
```

**401** – Invalid or expired token

Content-Type: `application/json`

```json
{
  "ok": false,
  "error": "string"
}
```

**429** – Too many refresh attempts

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/auth/session/refresh" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"refreshToken\": \"string\"
}"
```

## DELETE `/auth/sidebar/preferences`

Delete a role sidebar variant

Removes the role variant for the current tenant + locale. Idempotent. Requires `auth.sidebar.manage`.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Responses

**200** – Variant deleted (or never existed)

Content-Type: `application/json`

```json
{
  "ok": true,
  "scope": {
    "type": "user"
  }
}
```

**400** – Missing roleId query parameter

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Missing features

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Role not found in current tenant scope

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/auth/sidebar/preferences" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/auth/sidebar/preferences`

Get sidebar preferences

Returns sidebar customization for the current user (default) or the specified role (`?roleId=…`, requires `auth.sidebar.manage`).

**Tags:** Authentication & Accounts

**Requires authentication.**

### Responses

**200** – Current sidebar configuration

Content-Type: `application/json`

```json
{
  "locale": "string",
  "settings": {
    "version": 1,
    "groupOrder": [
      "string"
    ],
    "groupLabels": {
      "key": "string"
    },
    "itemLabels": {
      "key": "string"
    },
    "hiddenItems": [
      "string"
    ],
    "itemOrder": {
      "key": [
        "string"
      ]
    }
  },
  "canApplyToRoles": true,
  "roles": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "hasPreference": true
    }
  ],
  "scope": {
    "type": "user"
  },
  "updatedAt": null
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Missing features for role-scope read

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Role not found in current tenant scope

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/auth/sidebar/preferences" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/auth/sidebar/preferences`

Update sidebar preferences

Updates sidebar configuration. With `scope.type === "user"` (default) writes the calling user's personal preferences and may optionally apply the same settings to selected roles via `applyToRoles[]`. With `scope.type === "role"` writes the named role variant directly (requires `auth.sidebar.manage`); `applyToRoles[]` and `clearRoleIds[]` are rejected in this mode.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Preferences saved

Content-Type: `application/json`

```json
{
  "locale": "string",
  "settings": {
    "version": 1,
    "groupOrder": [
      "string"
    ],
    "groupLabels": {
      "key": "string"
    },
    "itemLabels": {
      "key": "string"
    },
    "hiddenItems": [
      "string"
    ],
    "itemOrder": {
      "key": [
        "string"
      ]
    }
  },
  "canApplyToRoles": true,
  "roles": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "hasPreference": true
    }
  ],
  "scope": {
    "type": "user"
  },
  "updatedAt": null,
  "appliedRoles": [
    "00000000-0000-4000-8000-000000000000"
  ],
  "clearedRoles": [
    "00000000-0000-4000-8000-000000000000"
  ]
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Missing features for role-wide updates

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Role not found in current tenant scope

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/auth/sidebar/preferences" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## GET `/auth/sidebar/variants`

List sidebar variants

Returns the named sidebar variants saved by the current user for the current tenant + locale.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Responses

**200** – Variant list

Content-Type: `application/json`

```json
{
  "locale": "string",
  "variants": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "isActive": true,
      "settings": {
        "version": 1,
        "groupOrder": [
          "string"
        ],
        "groupLabels": {
          "key": "string"
        },
        "itemLabels": {
          "key": "string"
        },
        "hiddenItems": [
          "string"
        ],
        "itemOrder": {
          "key": [
            "string"
          ]
        }
      },
      "createdAt": "string",
      "updatedAt": null
    }
  ]
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/auth/sidebar/variants" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/auth/sidebar/variants`

Create a sidebar variant

Creates a new variant. If `name` is omitted or blank, an auto-name like "My preferences", "My preferences 2", … is assigned.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Variant created

Content-Type: `application/json`

```json
{
  "locale": "string",
  "variant": {
    "id": "00000000-0000-4000-8000-000000000000",
    "name": "string",
    "isActive": true,
    "settings": {
      "version": 1,
      "groupOrder": [
        "string"
      ],
      "groupLabels": {
        "key": "string"
      },
      "itemLabels": {
        "key": "string"
      },
      "hiddenItems": [
        "string"
      ],
      "itemOrder": {
        "key": [
          "string"
        ]
      }
    },
    "createdAt": "string",
    "updatedAt": null
  }
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/auth/sidebar/variants" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## DELETE `/auth/sidebar/variants/{id}`

Delete a sidebar variant

Soft-deletes the variant (sets deleted_at).

**Tags:** Authentication & Accounts

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Variant deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Variant not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/auth/sidebar/variants/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/auth/sidebar/variants/{id}`

Get a sidebar variant

**Tags:** Authentication & Accounts

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Variant

Content-Type: `application/json`

```json
{
  "locale": "string",
  "variant": {
    "id": "00000000-0000-4000-8000-000000000000",
    "name": "string",
    "isActive": true,
    "settings": {
      "version": 1,
      "groupOrder": [
        "string"
      ],
      "groupLabels": {
        "key": "string"
      },
      "itemLabels": {
        "key": "string"
      },
      "hiddenItems": [
        "string"
      ],
      "itemOrder": {
        "key": [
          "string"
        ]
      }
    },
    "createdAt": "string",
    "updatedAt": null
  }
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Variant not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/auth/sidebar/variants/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/auth/sidebar/variants/{id}`

Update a sidebar variant

Updates the variant's name, settings, and/or isActive flag. Setting `isActive: true` deactivates other variants in the same scope (only one active per user/tenant/locale).

**Tags:** Authentication & Accounts

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Variant updated

Content-Type: `application/json`

```json
{
  "locale": "string",
  "variant": {
    "id": "00000000-0000-4000-8000-000000000000",
    "name": "string",
    "isActive": true,
    "settings": {
      "version": 1,
      "groupOrder": [
        "string"
      ],
      "groupLabels": {
        "key": "string"
      },
      "itemLabels": {
        "key": "string"
      },
      "hiddenItems": [
        "string"
      ],
      "itemOrder": {
        "key": [
          "string"
        ]
      }
    },
    "createdAt": "string",
    "updatedAt": null
  }
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Variant not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/auth/sidebar/variants/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## DELETE `/auth/users`

Delete user

Deletes a user by identifier. Rejected when the target is the last active holder of a protected role in the tenant. Undo support is provided via the command bus.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | query | any | Required. User identifier |

### Responses

**200** – User deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – User cannot be deleted, or is the last active holder of a protected role

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – User not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/auth/users?id=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/auth/users`

List users

Returns users for the effective selected tenant and organization scope. Search matches email, organization name, and role name. Super administrators may scope the response via the topbar context, organization filters, or role filters. Pass scopeToActiveOrganization=1 to restrict results to the caller's active organization (used by recipient/assignee pickers so suggestions stay within the org that owns the resulting record).

**Tags:** Authentication & Accounts

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | query | any | Optional |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| name | query | any | Optional |
| organizationId | query | any | Optional |
| scopeToActiveOrganization | query | any | Optional |
| roleIds | query | any | Optional |

### Responses

**200** – User collection

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "email": "user@example.com",
      "name": null,
      "organizationId": null,
      "organizationName": null,
      "tenantId": null,
      "tenantName": null,
      "roles": [
        "string"
      ],
      "isConfirmed": true,
      "updatedAt": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/auth/users?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/auth/users`

Create user

Creates a new confirmed user within the specified organization, optional display name, and optional roles.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "email": "user@example.com",
  "name": null,
  "organizationId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**201** – User created

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

**400** – Invalid payload or duplicate email

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Attempted to assign privileged roles

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/auth/users" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"email\": \"user@example.com\",
  \"name\": null,
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## PUT `/auth/users`

Update user

Updates profile fields including display name, organization assignment, credentials, or role memberships. A destination organization must be within the caller's descendant-expanded organization scope. Retained and newly assigned roles must belong to the destination tenant and be grantable by the caller. Setting isConfirmed=false deactivates the account: the user can no longer sign in and every active session is revoked; isConfirmed=true reactivates it. A tenant cannot drop below a protected role's minimum active holder count, so revoking the role from, deactivating, moving, or deleting the last active administrator is rejected.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "name": null
}
```

### Responses

**200** – User updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Invalid payload, duplicate email, or the update would remove the last active holder of a protected role

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Destination organization is outside caller scope, or a retained or assigned role is not grantable

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – User or destination organization not found in the caller tenant scope

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/auth/users" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"name\": null
}"
```

## GET `/auth/users/acl`

Fetch user ACL

Returns custom ACL overrides for a user within the current tenant, if any.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| userId | query | any | Required |

### Responses

**200** – User ACL entry

Content-Type: `application/json`

```json
{
  "hasCustomAcl": true,
  "isSuperAdmin": true,
  "features": [
    "string"
  ],
  "organizations": null,
  "updatedAt": null
}
```

**400** – Invalid user id

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/auth/users/acl?userId=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/auth/users/acl`

Update user ACL

Updates a per-user ACL override. Omitted super admin, feature, and organization fields preserve their stored values. An organization-scoped non-super-admin override requires at least one feature grant.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "userId": "00000000-0000-4000-8000-000000000000",
  "organizations": null
}
```

### Responses

**200** – User ACL updated

Content-Type: `application/json`

```json
{
  "ok": true,
  "sanitized": true
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Insufficient privileges to modify ACL

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/auth/users/acl" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"userId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizations\": null
}"
```

## GET `/auth/users/consents`

List user consents

Returns all consent records for a given user, with integrity verification status.

**Tags:** Auth

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| userId | query | any | Required |

### Responses

**200** – Consent list returned

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/auth/users/consents?userId=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/auth/users/resend-invite`

Resend invitation email

Resends the invitation email to a user who has not yet set up their password. Generates a new 48-hour setup token and invalidates prior tokens.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Invite email sent

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Invalid request origin

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – User not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**409** – User already has a password

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**422** – Validation error

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**429** – Rate limit exceeded

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Invitation email origin is not configured

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/auth/users/resend-invite" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/closare_communications/vehicles`

Read the scoped vehicle roster or one vehicle's bounded history

**Tags:** Vehicle communications

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| operationId | query | any | Optional |
| before | query | any | Optional |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |

### Responses

**200** – Roster page, or the selected vehicle history with a null conversationId when no transcript exists yet

Content-Type: `application/json`

**403** – Source or feature denied

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_communications/vehicles?page=1&pageSize=30&search=" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/closare_communications/vehicles`

Send an explicitly requested driver message to the verified current vehicle target

**Tags:** Vehicle communications

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "conversationId": "string",
  "requestId": "string",
  "text": "string",
  "targetToken": "string"
}
```

### Responses

**200** – Durable delivery result; provider acceptance is not driver receipt

Content-Type: `application/json`

**409** – Target changed or retry requires reconciliation

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_communications/vehicles" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"conversationId\": \"string\",
  \"requestId\": \"string\",
  \"text\": \"string\",
  \"targetToken\": \"string\"
}"
```

## POST `/closare_communications/vehicles/open`

Materialize the vehicle transcript so a message can be addressed to it

**Tags:** Vehicle communications

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "operationId": "string"
}
```

### Responses

**200** – conversationId and the current target token

Content-Type: `application/json`

**403** – Source or feature denied

Content-Type: `application/json`

**409** – Vehicle is not currently messageable

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_communications/vehicles/open" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"operationId\": \"string\"
}"
```

## POST `/closare_communications/vehicles/read`

Record how far the current operator has read a vehicle transcript

**Tags:** Vehicle communications

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "operationId": "string"
}
```

### Responses

**200** – Marker position; null conversationId when no transcript exists yet

Content-Type: `application/json`

**403** – Source or feature denied

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_communications/vehicles/read" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"operationId\": \"string\"
}"
```

## DELETE `/closare_connectors/connection`

Retired connection API: configure native integrations and tool policies

**Tags:** Cowork tools

**Requires authentication.**

### Responses

**204** – Success

**410** – Use Open Mercato integrations

Content-Type: `application/json`

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/closare_connectors/connection" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_connectors/connection`

Retired connection API: configure native integrations and tool policies

**Tags:** Cowork tools

**Requires authentication.**

### Responses

**200** – Success response

Content-Type: `application/json`

**410** – Use Open Mercato integrations

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_connectors/connection" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/closare_connectors/connection`

Retired connection API: configure native integrations and tool policies

**Tags:** Cowork tools

**Requires authentication.**

### Responses

**201** – Success response

Content-Type: `application/json`

**410** – Use Open Mercato integrations

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_connectors/connection" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/closare_connectors/connection`

Retired connection API: configure native integrations and tool policies

**Tags:** Cowork tools

**Requires authentication.**

### Responses

**200** – Success response

Content-Type: `application/json`

**410** – Use Open Mercato integrations

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/closare_connectors/connection" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_connectors/providers`

List registered connector providers for scoped setup

**Tags:** Closare Connections

**Requires authentication.**

### Responses

**200** – Provider identity and native credential destination; no credentials

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_connectors/providers" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/closare_connectors/tool-access`

Set organization tool access independently of connection and approval

**Tags:** Cowork tools

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "integrationSlug": "string",
  "toolName": "string",
  "enabled": true,
  "expectedUpdatedAt": null
}
```

### Responses

**200** – Updated setting and optimistic version

Content-Type: `application/json`

**409** – Policy changed since read

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/closare_connectors/tool-access" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"integrationSlug\": \"string\",
  \"toolName\": \"string\",
  \"enabled\": true,
  \"expectedUpdatedAt\": null
}"
```

## GET `/closare_connectors/tools`

List installed coworker tools and effective approval policies

**Tags:** Cowork tools

**Requires authentication.**

### Responses

**200** – Public descriptors, availability, policy and configuration capability

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_connectors/tools" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_cowork/approval/{id}`

Read a prepared action as its owner or authorized reviewer

**Tags:** Closare Cowork

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Approval card without conversation history

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_cowork/approval/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/closare_cowork/approval/{id}`

Decide and execute an exact persisted approval

**Tags:** Closare Cowork

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "approved": true
}
```

### Responses

**200** – Persisted decision and execution result

Content-Type: `application/json`

**409** – Stale decision version

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_cowork/approval/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"approved\": true
}"
```

## GET `/closare_cowork/apps`

List the apps offered in the Cowork sidebar for this scope

**Tags:** Cowork

**Requires authentication.**

### Responses

**200** – Operation types declared by the entitled tenant module, record lists the user may open, and custom apps

Content-Type: `application/json`

```json
{
  "operationTypes": [
    {
      "kind": "string",
      "label": "string",
      "icon": "truck",
      "href": "string"
    }
  ],
  "records": [
    {
      "id": "companies",
      "label": "string",
      "labelKey": "string",
      "icon": "building",
      "href": "string"
    }
  ],
  "defaultKind": null,
  "customApps": []
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_cowork/apps" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_cowork/automations/actions`

Read scoped cross-Operation actions

**Tags:** Closare Cowork

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| status | query | any | Optional |

### Responses

**200** – Action page (most recently updated first) with parent Operation kind and label, plus per-status counts

Content-Type: `application/json`

**400** – Invalid pagination or status

Content-Type: `application/json`

**403** – Work access denied

Content-Type: `application/json`

**503** – Work owner unavailable

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_cowork/automations/actions?page=1&pageSize=25" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_cowork/automations/activity`

Read current owner background activity

**Tags:** Closare Cowork

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| kind | query | any | Optional |

### Responses

**200** – Bounded activity page, kind counts and running count. Live scope only; email content is freshly authorized.

Content-Type: `application/json`

**400** – Invalid pagination or kind

Content-Type: `application/json`

**403** – Read or source access denied

Content-Type: `application/json`

**503** – Required activity source unavailable

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_cowork/automations/activity?page=1&pageSize=25" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_cowork/automations/observations`

Read scoped cross-Operation observations

**Tags:** Closare Cowork

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| from | query | any | Optional |
| to | query | any | Optional |
| type | query | any | Optional |

### Responses

**200** – Observation page, available types and applied UTC filters

Content-Type: `application/json`

**400** – Invalid pagination, type or UTC date range (maximum 366 inclusive days)

Content-Type: `application/json`

**403** – Work access denied

Content-Type: `application/json`

**503** – Work owner unavailable

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_cowork/automations/observations?page=1&pageSize=25" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_cowork/automations/schedules`

Read owned automation schedules

**Tags:** Closare Cowork

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |

### Responses

**200** – Schedules, supported skills and management capability

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_cowork/automations/schedules?page=1&pageSize=25" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/closare_cowork/automations/schedules`

Create an owned schedule

**Tags:** Closare Cowork

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "name": "string",
  "prompt": "string",
  "intervalMinutes": 1,
  "requestId": "string"
}
```

### Responses

**201** – Idempotent schedule result

Content-Type: `application/json`

**503** – Runtime or encryption unavailable

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_cowork/automations/schedules" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"name\": \"string\",
  \"prompt\": \"string\",
  \"intervalMinutes\": 1,
  \"requestId\": \"string\"
}"
```

## DELETE `/closare_cowork/automations/schedules/{id}`

Tombstone an owned schedule

**Tags:** Closare Cowork

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "requestId": "string",
  "updatedAt": "string"
}
```

### Responses

**200** – Deleted; execution history retained

Content-Type: `application/json`

**409** – Stale version

Content-Type: `application/json`

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/closare_cowork/automations/schedules/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"requestId\": \"string\",
  \"updatedAt\": \"string\"
}"
```

## PATCH `/closare_cowork/automations/schedules/{id}`

Edit or toggle an owned schedule

**Tags:** Closare Cowork

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "name": "string",
  "prompt": "string",
  "intervalMinutes": 1,
  "requestId": "string",
  "updatedAt": "string"
}
```

### Responses

**200** – Versioned schedule result

Content-Type: `application/json`

**409** – Stale version or changed request identity

Content-Type: `application/json`

### Example

```bash
curl -X PATCH "https://demo-carrier.closare.com/api/closare_cowork/automations/schedules/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"name\": \"string\",
  \"prompt\": \"string\",
  \"intervalMinutes\": 1,
  \"requestId\": \"string\",
  \"updatedAt\": \"string\"
}"
```

## POST `/closare_cowork/automations/schedules/{id}/run`

Queue one durable manual schedule run

**Tags:** Closare Cowork

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "requestId": "string",
  "updatedAt": "string"
}
```

### Responses

**200** – Durable execution and session identifiers; recurring cursor unchanged

Content-Type: `application/json`

**409** – Stale version or existing active run

Content-Type: `application/json`

**503** – Runtime unavailable

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_cowork/automations/schedules/:id/run" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"requestId\": \"string\",
  \"updatedAt\": \"string\"
}"
```

## GET `/closare_cowork/automations/schedules/{id}/runs/{executionId}`

Read an owned scheduled run report

**Tags:** Closare Cowork

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| executionId | path | any | Required |

### Responses

**200** – Run status, safe usage metadata and bounded final assistant report. No transcript or tool payloads.

Content-Type: `application/json`

**404** – Owned schedule or run unavailable

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_cowork/automations/schedules/:id/runs/:executionId" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_cowork/configuration`

Get authorized Cowork availability

**Tags:** Cowork

**Requires authentication.**

### Responses

**200** – Cowork configuration

Content-Type: `application/json`

```json
{
  "configured": true,
  "canChat": true,
  "coworkerId": null,
  "updatedAt": null,
  "sandbox": null,
  "runtimeReady": true,
  "runtimeState": "not_connected"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_cowork/configuration" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_cowork/inbox/email`

Read current user mailbox information and email in the active Cowork organization

**Tags:** Cowork

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| view | query | any | Optional |
| mailboxId | query | any | Optional |
| id | query | any | Optional |
| threadId | query | any | Optional |
| folder | query | any | Optional |
| search | query | any | Optional |
| page | query | any | Optional |
| pageSize | query | any | Optional |

### Responses

**200** – Owned mailboxes, a page of emails, or a full email selected by id

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "label": "string",
      "email": null,
      "provider": "string",
      "status": "string",
      "isActive": true,
      "isPrimary": true,
      "lastPolledAt": null
    }
  ]
}
```

**400** – Invalid query

Content-Type: `application/json`

**401** – Authentication required

Content-Type: `application/json`

**403** – Required feature or organization scope denied

Content-Type: `application/json`

**404** – Mailbox or email not available to this user

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_cowork/inbox/email?view=messages&folder=inbox&search=&page=1&pageSize=25" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_cowork/operation/{id}/action/{actionId}/story`

Read one objective end to end: trigger with its frozen snapshot, wakes, observations, messages and outcome

**Tags:** Closare Cowork

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| actionId | path | any | Required |

### Responses

**200** – action, time-ordered events, truncated

Content-Type: `application/json`

**400** – Invalid operation or objective identifier

Content-Type: `application/json`

**403** – Cowork or Work access denied

Content-Type: `application/json`

**404** – Objective not on this Operation or not in scope

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_cowork/operation/:id/action/:actionId/story" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_cowork/operation/{id}/activity`

Read an Operation as situations: open ones, or a page of closed situations, coworker turns and loose records

**Tags:** Closare Cowork

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – items (SITUATION | TURN | RECORD entries, newest first), nextCursor

Content-Type: `application/json`

**400** – Invalid operation identifier or query

Content-Type: `application/json`

**403** – Cowork or Work access denied

Content-Type: `application/json`

**404** – Operation not in scope

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_cowork/operation/:id/activity" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_cowork/operation/{id}/activity/summary`

Summarize how an Operation's situations of the last days ended

**Tags:** Closare Cowork

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – days, total, open, byResolution, escalated, falseAlarms, medianClearMs

Content-Type: `application/json`

**400** – Invalid operation identifier or query

Content-Type: `application/json`

**403** – Cowork or Work access denied

Content-Type: `application/json`

**404** – Operation not in scope

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_cowork/operation/:id/activity/summary" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_cowork/operation/{id}/wake`

Read the bounded operation wake history recorded for one Operation

**Tags:** Closare Cowork

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Most recent operation wakes, newest first

Content-Type: `application/json`

**400** – Invalid operation identifier

Content-Type: `application/json`

**403** – Cowork or Work access denied

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_cowork/operation/:id/wake" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_cowork/record-conversation`

Read the current user’s conversation on a record, without creating it

**Tags:** Closare Cowork

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| operationId | query | any | Required |

### Responses

**200** – record (operationId, kind, label), session or null, runningExecutionId, lastMessageAt

Content-Type: `application/json`

**403** – The record is not visible to the user (a missing record answers the same)

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_cowork/record-conversation?operationId=string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/closare_cowork/record-conversation`

Open the current user’s conversation on a record

Returns the existing ACTIVE conversation, or creates it. One per user and record; a concurrent open returns the same conversation. Does not start a model execution.

**Tags:** Closare Cowork

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "operationId": "string"
}
```

### Responses

**200** – record, session, created

Content-Type: `application/json`

**403** – The record is not visible to the user

Content-Type: `application/json`

**409** – The coworker is not configured

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_cowork/record-conversation" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"operationId\": \"string\"
}"
```

## GET `/closare_cowork/run/{id}`

Resolve one coworker run to the conversation that holds it

**Tags:** Closare Cowork

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Run identity and its conversation

Content-Type: `application/json`

**404** – No such run in this organization

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_cowork/run/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_cowork/session`

List the current user’s conversations in the selected organization

**Tags:** Closare Cowork

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| surface | query | any | Optional |
| sorting | query | any | Optional |
| cursor | query | any | Optional |
| limit | query | any | Optional |

### Responses

**200** – items and nextCursor; createdAt descending by default. Optional surface=general limits to unanchored CHAT sessions; sorting=activity orders lastMessageAt (createdAt fallback) descending, then ID. Cursor must belong to the same filtered surface.

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_cowork/session?limit=30" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/closare_cowork/session`

Create an empty conversation

clientRequestId is a UUID used as the session ID. The same owner and normalized title may replay; conflicting reuse returns 409. Does not start a model execution.

**Tags:** Closare Cowork

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "clientRequestId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**201** – sessionId, updatedAt, replayed

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_cowork/session" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"clientRequestId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/closare_cowork/session/{id}`

Read an owned conversation and pending interaction IDs

**Tags:** Closare Cowork

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Session summary, activeExecution, latestFailure (executionId and safe reason code, or null), triageItemId (EMAIL_TRIAGE runs only, else null), pendingQuestionIds, pendingApprovalIds

Content-Type: `application/json`

**404** – No accessible conversation

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_cowork/session/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_cowork/session/{id}/approvals`

Read approvals in an owned conversation

**Tags:** Closare Cowork

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Persisted approval cards and decision permissions

Content-Type: `application/json`

**404** – Conversation is not accessible

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_cowork/session/string/approvals" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/closare_cowork/session/{id}/cancel`

Cancel an exact execution in an owned conversation

**Tags:** Closare Cowork

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "clientRequestId": "00000000-0000-4000-8000-000000000000",
  "executionId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – executionId and terminal status, or null when no matching execution exists

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_cowork/session/00000000-0000-4000-8000-000000000000/cancel" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"clientRequestId\": \"00000000-0000-4000-8000-000000000000\",
  \"executionId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/closare_cowork/session/{id}/events`

Replay safe persisted conversation events

**Tags:** Closare Cowork

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| after | query | any | Optional |
| limit | query | any | Optional |

### Responses

**200** – items with decimal sequence, type, safe payload, and nextCursor

Content-Type: `application/json`

**404** – Session or cursor is inaccessible

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_cowork/session/00000000-0000-4000-8000-000000000000/events?after=0&limit=100" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_cowork/session/{id}/execution`

Read the latest safe execution state after recovery

**Tags:** Closare Cowork

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – execution id, status and phase, or null

Content-Type: `application/json`

**404** – Session is inaccessible

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_cowork/session/00000000-0000-4000-8000-000000000000/execution" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_cowork/session/{id}/image`

Read a private image in an owned conversation

**Tags:** Closare Cowork

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| attachmentId | query | any | Required |

### Responses

**200** – Image bytes

Content-Type: `application/json`

**404** – Inaccessible image or conversation

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_cowork/session/00000000-0000-4000-8000-000000000000/image?attachmentId=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/closare_cowork/session/{id}/image`

Upload a JPEG, PNG or WebP image (multipart file, maximum 10 MiB)

**Tags:** Closare Cowork

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**201** – Attachment ID and owner-scoped image URL

Content-Type: `application/json`

**400** – Invalid image

Content-Type: `application/json`

**413** – Image or storage quota exceeded

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_cowork/session/00000000-0000-4000-8000-000000000000/image" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_cowork/session/{id}/message`

Read persisted messages in an owned conversation

**Tags:** Closare Cowork

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| before | query | any | Optional |
| limit | query | any | Optional |

### Responses

**200** – items in chronological order and nextCursor for older messages

Content-Type: `application/json`

**404** – No accessible session or cursor

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_cowork/session/00000000-0000-4000-8000-000000000000/message?limit=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/closare_cowork/session/{id}/message`

Send a message to the configured Cowork runtime

**Tags:** Closare Cowork

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "clientRequestId": "00000000-0000-4000-8000-000000000000",
  "content": "string"
}
```

### Responses

**202** – Durable executionId, messageId, sessionId and replayed flag

Content-Type: `application/json`

**409** – Turn already running or conflicting retry

Content-Type: `application/json`

**503** – Runtime not configured

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_cowork/session/00000000-0000-4000-8000-000000000000/message" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"clientRequestId\": \"00000000-0000-4000-8000-000000000000\",
  \"content\": \"string\"
}"
```

## GET `/closare_cowork/situations`

List the Operations that have open situations, with counts and the nearest deadline

**Tags:** Closare Cowork

**Requires authentication.**

### Responses

**200** – items: operationId, open, needsAttention, nextDeadline

Content-Type: `application/json`

**400** – Invalid query

Content-Type: `application/json`

**403** – Cowork or Work access denied

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_cowork/situations" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_cowork/skill`

List retained skills and runtime availability

**Tags:** Cowork

**Requires authentication.**

### Responses

**200** – Scoped skill manifest

Content-Type: `application/json`

```json
{
  "items": [
    {
      "name": "string",
      "runnable": true,
      "missingCapabilities": [
        "string"
      ]
    }
  ]
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_cowork/skill" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/closare_cowork/tool-policy`

Reset scoped tool approval policy to false

**Tags:** Cowork tools

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "integrationSlug": "string",
  "toolName": "string",
  "expectedUpdatedAt": null
}
```

### Responses

**200** – Default policy

Content-Type: `application/json`

**409** – Policy changed since read

Content-Type: `application/json`

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/closare_cowork/tool-policy" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"integrationSlug\": \"string\",
  \"toolName\": \"string\",
  \"expectedUpdatedAt\": null
}"
```

## GET `/closare_cowork/tool-policy`

Read effective tool approval policy

**Tags:** Cowork tools

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| integrationSlug | query | any | Required |
| toolName | query | any | Required |

### Responses

**200** – Effective setting, source and optimistic version

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_cowork/tool-policy?integrationSlug=string&toolName=string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/closare_cowork/tool-policy`

Set scoped tool approval policy

**Tags:** Cowork tools

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "integrationSlug": "string",
  "toolName": "string",
  "requiresApproval": true,
  "expectedUpdatedAt": null
}
```

### Responses

**200** – Saved override

Content-Type: `application/json`

**409** – Policy changed since read

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/closare_cowork/tool-policy" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"integrationSlug\": \"string\",
  \"toolName\": \"string\",
  \"requiresApproval\": true,
  \"expectedUpdatedAt\": null
}"
```

## GET `/closare_cowork/triage`

Read owner-scoped email triage history

**Tags:** Closare Cowork

**Requires authentication.**

### Responses

**200** – Authorized email triage records

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_cowork/triage" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_cowork/triage/{id}`

Read owner-scoped email triage [id]

**Tags:** Closare Cowork

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Authorized email triage records with canAct and canReply capability flags

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_cowork/triage/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/closare_cowork/triage/{id}/action`

Retry, reply to, or resolve owned email triage with explicit version

**Tags:** Closare Cowork

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "clientRequestId": "string",
  "expectedVersion": 1,
  "transition": "retry"
}
```

### Responses

**200** – Versioned triage result

Content-Type: `application/json`

**409** – Stale decision or retry conflict

Content-Type: `application/json`

**502** – Operator reply was not sent

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_cowork/triage/:id/action" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"clientRequestId\": \"string\",
  \"expectedVersion\": 1,
  \"transition\": \"retry\"
}"
```

## GET `/closare_cowork/triage/mailbox`

Read owner-scoped email triage mailbox

**Tags:** Closare Cowork

**Requires authentication.**

### Responses

**200** – Authorized email triage records

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_cowork/triage/mailbox" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/closare_cowork/triage/mailbox`

Configure an owned mailbox triage opt-in

**Tags:** Closare Cowork

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "channelId": "string",
  "enabled": true,
  "expectedVersion": 1,
  "clientRequestId": "string"
}
```

### Responses

**200** – Versioned mailbox configuration

Content-Type: `application/json`

**409** – Stale configuration

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_cowork/triage/mailbox" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"channelId\": \"string\",
  \"enabled\": true,
  \"expectedVersion\": 1,
  \"clientRequestId\": \"string\"
}"
```

## GET `/closare_fleet/monitors`

Read the organization's monitors: switch, parameters, bounds and availability

**Tags:** Fleet monitoring

**Requires authentication.**

### Responses

**200** – Detectors (Fleet's and contributed) and event processors, each with what its vehicles can feed

Content-Type: `application/json`

**403** – Not entitled to Fleet monitoring, or missing closare_fleet.monitoring.manage

Content-Type: `application/json`

**503** – Stored settings are no longer valid; clear them through the settings route

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_fleet/monitors" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_fleet/settings`

Read the organization's Fleet settings with their origins and bounds

**Tags:** Fleet monitoring

**Requires authentication.**

### Responses

**200** – Effective value and origin of every setting, bounds, and the version to save against

Content-Type: `application/json`

**403** – Not entitled to Fleet monitoring, or missing closare_fleet.monitoring.manage

Content-Type: `application/json`

**503** – Stored settings are no longer valid: the body gives the reason (`values`, `schemaVersion` or `unreadable`), the keys at fault, the keys one save sets to null to recover (`clear`), and the version that save sends

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_fleet/settings" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/closare_fleet/settings`

Save the organization's own values for some Fleet settings

**Tags:** Fleet monitoring

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "updatedAt": null,
  "values": {}
}
```

### Responses

**200** – The effective settings after the save

Content-Type: `application/json`

**400** – A key that is not declared, is set by the tenant module only, or is out of bounds; the body names the key and its range

Content-Type: `application/json`

**403** – Not entitled to Fleet monitoring, or missing closare_fleet.monitoring.manage

Content-Type: `application/json`

**409** – The settings changed since they were read

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/closare_fleet/settings" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"updatedAt\": null,
  \"values\": {}
}"
```

## GET `/closare_fleet/sources`

Read Fleet sources and their event health

**Tags:** Fleet monitoring

**Requires authentication.**

### Responses

**200** – Scoped sources with failed and pending event counts

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_fleet/sources" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/closare_fleet/sources`

Configure a Fleet source for a telemetry provider

**Tags:** Fleet monitoring

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "requestId": "string",
  "provider": "string",
  "enabled": false
}
```

### Responses

**201** – Created source, disabled by default

Content-Type: `application/json`

**400** – Provider not available in this build

Content-Type: `application/json`

**409** – Missing native connection or duplicate provider

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_fleet/sources" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"requestId\": \"string\",
  \"provider\": \"string\",
  \"enabled\": false
}"
```

## PATCH `/closare_fleet/sources/{id}`

Enable or disable a Fleet source; history is retained

**Tags:** Fleet monitoring

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "requestId": "string",
  "updatedAt": "string",
  "enabled": true
}
```

### Responses

**200** – Versioned source result

Content-Type: `application/json`

**409** – Stale source or unavailable connection

Content-Type: `application/json`

### Example

```bash
curl -X PATCH "https://demo-carrier.closare.com/api/closare_fleet/sources/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"requestId\": \"string\",
  \"updatedAt\": \"string\",
  \"enabled\": true
}"
```

## GET `/closare_fleet/sources/{id}/activities`

Read up to twenty failed source events without payloads

**Tags:** Fleet monitoring

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Failed event metadata and truncation indicator

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_fleet/sources/:id/activities" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/closare_fleet/sources/{id}/activities`

Retry one failed source event with a version fence

**Tags:** Fleet monitoring

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "requestId": "string",
  "updatedAt": "string",
  "activityId": "string"
}
```

### Responses

**200** – Failure returned to pending; source history retained

Content-Type: `application/json`

**409** – Event state changed

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_fleet/sources/:id/activities" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"requestId\": \"string\",
  \"updatedAt\": \"string\",
  \"activityId\": \"string\"
}"
```

## POST `/closare_fleet/sources/{id}/run`

Request a sweep of an enabled Fleet source

**Tags:** Fleet monitoring

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "requestId": "string",
  "updatedAt": "string"
}
```

### Responses

**200** – Durable request recorded; sweep queued

Content-Type: `application/json`

**409** – Disabled source or stale version

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_fleet/sources/:id/run" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"requestId\": \"string\",
  \"updatedAt\": \"string\"
}"
```

## POST `/closare_fleet/vehicles/{operationId}/eta`

Recalculate one vehicle arrival, inside the routing pilot and the monthly ceiling

**Tags:** Fleet monitoring

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| operationId | path | any | Required |

### Responses

**200** – The stored arrival, replaced when a route was bought or the leg changed; `source` says whether it was routed or estimated; `baseline` is the leg's priced plan, or null

Content-Type: `application/json`

**404** – Not a readable vehicle, or it has no commitment to estimate

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_fleet/vehicles/:operationId/eta" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_fleet/vehicles/{operationId}/routing`

Whether the routing pilot includes this vehicle

**Tags:** Fleet monitoring

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| operationId | path | any | Required |

### Responses

**200** – `pilotConfigured` and `inPilot` for this vehicle

Content-Type: `application/json`

**404** – Not a readable vehicle

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_fleet/vehicles/:operationId/routing" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_fleet/vehicles/analytics`

Vehicle monitor analytics: situations raised, their outcomes and durations in a window

**Tags:** Fleet monitoring

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| from | query | any | Optional |
| to | query | any | Optional |
| basis | query | any | Optional |
| monitors | query | any | Required |
| vehicle | query | any | Optional |
| dispatcher | query | any | Optional |
| country | query | any | Optional |
| pilot | query | any | Optional |
| bucket | query | any | Optional |
| tz | query | any | Required |
| page | query | any | Optional |

### Responses

**200** – Per-monitor totals, a bucketed series, top vehicles and one page of situations

Content-Type: `application/json`

**400** – Invalid query, or a window longer than 31 days

Content-Type: `application/json`

**403** – Work access denied, or this organization is not entitled to Fleet monitoring

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_fleet/vehicles/analytics?basis=raised&tz=string&page=1" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_maps/config`

Basemap configuration for operational maps in this deployment

**Tags:** Closare Maps

**Requires authentication.**

### Responses

**200** – Basemap style URLs (null when a configured style is invalid), optional satellite imagery, and required attribution

Content-Type: `application/json`

```json
{
  "basemap": {
    "styleUrl": null,
    "darkStyleUrl": null,
    "attribution": [
      {
        "label": "string",
        "href": "string"
      }
    ],
    "satellite": null
  }
}
```

**401** – Not authenticated

Content-Type: `application/json`

**403** – Scope or Work view permission denied

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_maps/config" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_maps/fuel-searches/{searchId}`

One fuel search as it was made: the corridor searched and the stations offered, frozen

**Tags:** Closare Maps

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| searchId | path | any | Required |

### Responses

**200** – The search, including a failed one; excursion is a straight-line round trip, never a road distance

Content-Type: `application/json`

```json
{
  "id": "string",
  "operationId": "string",
  "status": "OK",
  "detail": null,
  "stops": [
    {
      "placeId": "string",
      "name": "string",
      "brand": null,
      "lat": 1,
      "lng": 1,
      "aheadMeters": null,
      "excursionMeters": null,
      "detourBasis": "STRAIGHT_LINE",
      "offBrand": true
    }
  ],
  "corridor": null,
  "brandFallback": true,
  "position": null,
  "createdAt": "string"
}
```

**400** – Invalid search id

Content-Type: `application/json`

**401** – Not authenticated

Content-Type: `application/json`

**403** – Scope or Work view permission denied

Content-Type: `application/json`

**404** – Search not in this scope

Content-Type: `application/json`

**503** – Tenant encryption unavailable; searches are never read or written in plaintext

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_maps/fuel-searches/:searchId" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_maps/operations/{operationId}/trip`

Active trip of one vehicle operation: uncompleted tasks in visit order with their planned paths

**Tags:** Closare Maps

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| operationId | path | any | Required |

### Responses

**200** – Trip with an explicit status; provider failures are a status, never an error response

Content-Type: `application/json`

```json
{
  "status": "OK",
  "provider": null,
  "resolvedAt": "string",
  "tasks": [
    {
      "taskRef": "string",
      "sequence": 1,
      "title": "string",
      "address": null,
      "actionTag": null,
      "status": "string",
      "location": {
        "lat": 1,
        "lng": 1
      },
      "plannedDistanceMeters": null,
      "path": {
        "origin": "PREVIOUS_TASK",
        "status": "RESOLVED",
        "coordinates": [
          [
            1,
            1
          ]
        ]
      }
    }
  ]
}
```

**400** – Invalid operation id

Content-Type: `application/json`

**401** – Not authenticated

Content-Type: `application/json`

**403** – Scope or Work view permission denied

Content-Type: `application/json`

**404** – Operation not visible in this scope

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_maps/operations/:operationId/trip" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/closare_maps/positions`

Live positions for vehicle operations, read from each vehicle's own telemetry provider

**Tags:** Closare Maps

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "operationIds": [
    "string"
  ]
}
```

### Responses

**200** – One item per visible operation with an explicit telemetry status; provider failures are per item, never the request

Content-Type: `application/json`

```json
{
  "resolvedAt": "string",
  "items": [
    {
      "operationId": "string",
      "label": "string",
      "detailHref": null,
      "provider": null,
      "status": "LIVE",
      "position": null,
      "capabilities": {
        "activeTrip": true
      }
    }
  ],
  "missingOperationIds": [
    "string"
  ]
}
```

**400** – Invalid, duplicate or too many operation ids

Content-Type: `application/json`

**401** – Not authenticated

Content-Type: `application/json`

**403** – Scope or Work view permission denied

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_maps/positions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"operationIds\": [
    \"string\"
  ]
}"
```

## GET `/closare_pricing/definitions`

List pricing definitions

**Tags:** Pricing

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| kind | query | any | Optional |
| status | query | any | Optional |
| search | query | any | Optional |
| page | query | any | Optional |
| pageSize | query | any | Optional |

### Responses

**200** – `{ items: [{ id, kind, name, isDefault, archived, approvedRevision, draftRevision, updatedAt }], totalCount }`

Content-Type: `application/json`

**400** – `invalid` with `errors` by path

Content-Type: `application/json`

**403** – Pricing is not enabled for the organization, or closare_pricing.view is missing

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_pricing/definitions?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/closare_pricing/definitions`

Create a pricing definition

Creates the definition and its first draft (revision 1). A cost model and rules exist once per organization.

**Tags:** Pricing

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "kind": "mechanic",
  "name": "string"
}
```

### Responses

**201** – The definition detail: `{ definition, draft, approved, revisions, referencedBy }`

Content-Type: `application/json`

**400** – `invalid` with `errors` by path

Content-Type: `application/json`

**403** – Pricing is not enabled, or closare_pricing.configure or closare_pricing.view is missing

Content-Type: `application/json`

**409** – `singleton`: the organization already has its cost model or rules

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_pricing/definitions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"kind\": \"mechanic\",
  \"name\": \"string\"
}"
```

## DELETE `/closare_pricing/definitions/{id}`

Archive a pricing definition

**Tags:** Pricing

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| updatedAt | query | any | Required |

### Responses

**204** – Archived

**403** – Pricing is not enabled, or closare_pricing.configure or closare_pricing.view is missing

Content-Type: `application/json`

**404** – No such definition in this organization

Content-Type: `application/json`

**409** – `stale` (with `current`), `referenced` (with `referencedBy`), `defaultModel`, or `singleton` for the cost model and rules

Content-Type: `application/json`

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/closare_pricing/definitions/string?updatedAt=string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_pricing/definitions/{id}`

Read a pricing definition

**Tags:** Pricing

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – `{ definition, draft, approved, revisions, referencedBy }`

Content-Type: `application/json`

**403** – Pricing is not enabled, or closare_pricing.view is missing

Content-Type: `application/json`

**404** – No such definition in this organization

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_pricing/definitions/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/closare_pricing/definitions/{id}/approve`

Approve a pricing definition's draft

The draft becomes the approved revision (immutable) and the previous approved revision is superseded. Emits `closare_pricing.definition.approved`.

**Tags:** Pricing

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "draftRevisionId": "string",
  "updatedAt": "string"
}
```

### Responses

**200** – The definition detail

Content-Type: `application/json`

**400** – `invalid` with `errors` by path: shape, unknown or retired registry entries, params, route rules, references that are missing, not approved or archived, unknown currencies

Content-Type: `application/json`

**403** – Pricing is not enabled, or closare_pricing.configure or closare_pricing.view is missing

Content-Type: `application/json`

**404** – No such definition in this organization

Content-Type: `application/json`

**409** – `stale` (with `current`), `draftMismatch` (with `current`), `notDraft` or `archived`

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_pricing/definitions/string/approve" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"draftRevisionId\": \"string\",
  \"updatedAt\": \"string\"
}"
```

## POST `/closare_pricing/definitions/{id}/draft`

Start a new draft from the approved revision

**Tags:** Pricing

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "updatedAt": "string"
}
```

### Responses

**201** – The definition detail

Content-Type: `application/json`

**400** – `invalid` with `errors` by path, or `payloadTooLarge` (over 200 KB)

Content-Type: `application/json`

**403** – Pricing is not enabled, or closare_pricing.configure or closare_pricing.view is missing

Content-Type: `application/json`

**404** – No such definition in this organization

Content-Type: `application/json`

**409** – `stale` (with `current`), `draftExists`, `notApproved` or `archived`

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_pricing/definitions/string/draft" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"updatedAt\": \"string\"
}"
```

## PUT `/closare_pricing/definitions/{id}/draft`

Save a pricing definition's draft

**Tags:** Pricing

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "updatedAt": "string"
}
```

### Responses

**200** – The definition detail

Content-Type: `application/json`

**400** – `invalid` with `errors` by path, or `payloadTooLarge` (over 200 KB)

Content-Type: `application/json`

**403** – Pricing is not enabled, or closare_pricing.configure or closare_pricing.view is missing

Content-Type: `application/json`

**404** – No such definition in this organization

Content-Type: `application/json`

**409** – `stale` (with `current`), `notDraft` (approve or start a new draft first) or `archived`

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/closare_pricing/definitions/string/draft" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"updatedAt\": \"string\"
}"
```

## GET `/closare_pricing/fx/status`

Exchange-rate freshness for pricing

Per currency: the latest usable rate to PLN from the configured source (Open Mercato's stored rates), its Warsaw date, its age in days, its basis (`buy_sell_average` or `typeless`) and whether it is older than the maximum age.

**Tags:** Pricing

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| currencies | query | any | Optional. Comma-separated ISO 4217 codes; the organization's active currencies when left out. |

### Responses

**200** – `{ source, maxAgeDays, currencies: [{ code, latestDate, ageDays, basis, stale }] }`

Content-Type: `application/json`

**400** – `invalid`

Content-Type: `application/json`

**403** – Pricing is not enabled, or closare_pricing.view is missing

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_pricing/fx/status" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/closare_pricing/models/{id}/default`

Make a model the organization's default

**Tags:** Pricing

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "updatedAt": "string"
}
```

### Responses

**200** – The definition detail

Content-Type: `application/json`

**400** – `wrongKind`: not a model

Content-Type: `application/json`

**403** – Pricing is not enabled, or closare_pricing.configure or closare_pricing.view is missing

Content-Type: `application/json`

**404** – No such definition in this organization

Content-Type: `application/json`

**409** – `stale` (with `current`), `notApproved` or `archived`

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_pricing/models/string/default" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"updatedAt\": \"string\"
}"
```

## GET `/closare_pricing/rate-cards/{id}/entries`

List a rate card's entries

**Tags:** Pricing

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| revisionId | query | any | Optional |
| originCountry | query | any | Optional |
| destinationCountry | query | any | Optional |
| page | query | any | Optional |
| pageSize | query | any | Optional |

### Responses

**200** – `{ revisionId, items, totalCount, updatedAt }` (the definition's version)

Content-Type: `application/json`

**400** – `invalid`, or `wrongKind`: not a rate card

Content-Type: `application/json`

**403** – Pricing is not enabled, or closare_pricing.view is missing

Content-Type: `application/json`

**404** – No such rate card or revision in this organization

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_pricing/rate-cards/string/entries?page=1&pageSize=100" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/closare_pricing/rate-cards/{id}/entries`

Add a rate card entry to the draft

**Tags:** Pricing

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "entry": {
    "originCountry": "string",
    "originZones": null,
    "destinationCountry": "string",
    "destinationZones": null,
    "unit": "trip",
    "amount": 1,
    "currency": "string",
    "customerCompanyId": null,
    "equipmentFamily": null,
    "validFrom": null,
    "validUntil": null,
    "note": null
  },
  "updatedAt": "string"
}
```

### Responses

**201** – `{ entry, updatedAt }`: the entry and the definition's new version

Content-Type: `application/json`

**400** – `invalid` with `errors` by path, or `wrongKind`

Content-Type: `application/json`

**403** – Pricing is not enabled, or closare_pricing.configure or closare_pricing.view is missing

Content-Type: `application/json`

**404** – No such rate card in this organization

Content-Type: `application/json`

**409** – `stale` (with `current`), `notDraft` or `archived`

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_pricing/rate-cards/string/entries" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entry\": {
    \"originCountry\": \"string\",
    \"originZones\": null,
    \"destinationCountry\": \"string\",
    \"destinationZones\": null,
    \"unit\": \"trip\",
    \"amount\": 1,
    \"currency\": \"string\",
    \"customerCompanyId\": null,
    \"equipmentFamily\": null,
    \"validFrom\": null,
    \"validUntil\": null,
    \"note\": null
  },
  \"updatedAt\": \"string\"
}"
```

## DELETE `/closare_pricing/rate-cards/{id}/entries/{entryId}`

Remove a rate card entry from the draft

**Tags:** Pricing

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| entryId | path | any | Required |
| updatedAt | query | any | Required |

### Responses

**200** – `{ entry: null, updatedAt }`: the definition's new version

Content-Type: `application/json`

**403** – Pricing is not enabled, or closare_pricing.configure or closare_pricing.view is missing

Content-Type: `application/json`

**404** – No such rate card or entry in this organization

Content-Type: `application/json`

**409** – `stale` (with `current`), `notDraft` (the entry is not in the draft) or `archived`

Content-Type: `application/json`

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/closare_pricing/rate-cards/string/entries/string?updatedAt=string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/closare_pricing/rate-cards/{id}/entries/{entryId}`

Change a rate card entry of the draft

**Tags:** Pricing

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| entryId | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "entry": {
    "originCountry": "string",
    "originZones": null,
    "destinationCountry": "string",
    "destinationZones": null,
    "unit": "trip",
    "amount": 1,
    "currency": "string",
    "customerCompanyId": null,
    "equipmentFamily": null,
    "validFrom": null,
    "validUntil": null,
    "note": null
  },
  "updatedAt": "string"
}
```

### Responses

**200** – `{ entry, updatedAt }`

Content-Type: `application/json`

**400** – `invalid` with `errors` by path, or `wrongKind`

Content-Type: `application/json`

**403** – Pricing is not enabled, or closare_pricing.configure or closare_pricing.view is missing

Content-Type: `application/json`

**404** – No such rate card or entry in this organization

Content-Type: `application/json`

**409** – `stale` (with `current`), `notDraft` (the entry is not in the draft) or `archived`

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/closare_pricing/rate-cards/string/entries/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entry\": {
    \"originCountry\": \"string\",
    \"originZones\": null,
    \"destinationCountry\": \"string\",
    \"destinationZones\": null,
    \"unit\": \"trip\",
    \"amount\": 1,
    \"currency\": \"string\",
    \"customerCompanyId\": null,
    \"equipmentFamily\": null,
    \"validFrom\": null,
    \"validUntil\": null,
    \"note\": null
  },
  \"updatedAt\": \"string\"
}"
```

## GET `/closare_pricing/registry`

List pricing registry entries

Sources, units, adjustments, conditions, lane inputs and rules, built in and contributed by modules, each with its version, label key and params JSON schema. Entries of capabilities the organization lacks are hidden.

**Tags:** Pricing

**Requires authentication.**

### Responses

**200** – `{ source: [{ id, v, labelKey, paramsJsonSchema, needs?, selfScoped?, retired? }], unit: […], adjustment: […], condition: […], laneInput: […], rule: […] }`

Content-Type: `application/json`

**403** – Pricing is not enabled, or closare_pricing.view is missing

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_pricing/registry" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/closare_tendering/counterparties/{companyId}/memory`

Forget what is remembered about a sending company's tender files

**Tags:** Tendering

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| companyId | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "updatedAt": "string"
}
```

### Responses

**200** – Forgotten; the company's next reads are offered nothing

Content-Type: `application/json`

**403** – Tendering is not enabled for the organization, or closare_tendering.manage is missing

Content-Type: `application/json`

**404** – Nothing is remembered about this company

Content-Type: `application/json`

**409** – What is remembered changed since it was read

Content-Type: `application/json`

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/closare_tendering/counterparties/string/memory" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"updatedAt\": \"string\"
}"
```

## GET `/closare_tendering/counterparties/{companyId}/memory`

Read what is remembered about a sending company's tender files

**Tags:** Tendering

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| companyId | path | any | Required |

### Responses

**200** – `memory`: null when nothing is remembered; else the column choices offered to the company's next files, when and by whom they were last saved, and `updatedAt`, the version a forget names

Content-Type: `application/json`

```json
{
  "memory": null
}
```

**403** – Tendering is not enabled for the organization, or closare_tendering.view is missing

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_tendering/counterparties/string/memory" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_tendering/operations/{operationId}/tender`

Read the tender of a tender Operation

**Tags:** Tendering

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| operationId | path | any | Required |

### Responses

**200** – The tender, its current read with what it found, the filed read, what is remembered about its sending company, and `review`: where the coworker's review of the current read stands (`reviewing`, `idle`, or `unavailable` when its administrator cannot be woken for it). `canManage` and `canPrice` say whether the reader may file and re-read, and work out distances and prices

Content-Type: `application/json`

**403** – Tendering is not enabled for the organization, or closare_tendering.view is missing

Content-Type: `application/json`

**404** – No tender behind this Operation in this organization

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_tendering/operations/string/tender" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_tendering/parse-runs/{id}`

Read one read of a tender

**Tags:** Tendering

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – The run: status, reconciliation, sheets, columns, findings, questions, service asks, suggestions

Content-Type: `application/json`

**403** – Tendering is not enabled for the organization, or closare_tendering.view is missing

Content-Type: `application/json`

**404** – No such run in this organization

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_tendering/parse-runs/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_tendering/parse-runs/{id}/mapping`

Read how one read of a tender took its file apart

**Tags:** Tendering

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – The read (status, lanes, reconciliation, current or filed), the tender formats and the one detected or forced, the parser's open questions, and per sheet (at most 12): its job, lanes, whether it is set aside, its top 30 rows from where its data starts (cells from column A, 80 characters each), the header row the read used and the column letter of each lane field, as Excel numbers them. `gridsKept` false and no sheets when the read kept no copy of the cells

Content-Type: `application/json`

**403** – Tendering is not enabled for the organization, or closare_tendering.view is missing

Content-Type: `application/json`

**404** – No such read in this organization

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_tendering/parse-runs/string/mapping" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_tendering/tenders`

List tenders

**Tags:** Tendering

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| q | query | any | Optional |
| direction | query | any | Optional |
| intakeStatus | query | any | Optional |
| counterpartyCompanyId | query | any | Optional |
| deadlineFrom | query | any | Optional |
| deadlineTo | query | any | Optional |
| archived | query | any | Optional |
| sort | query | any | Optional |
| cursor | query | any | Optional |
| limit | query | any | Optional |

### Responses

**200** – Tenders with their lane count, reconciliation status and current read; `nextCursor` continues the list. `canManage` and `upload` (accepted types and size caps) drive the upload action

Content-Type: `application/json`

**400** – An unknown filter or a malformed cursor

Content-Type: `application/json`

**403** – Tendering is not enabled for the organization, or closare_tendering.view is missing

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_tendering/tenders?direction=received&archived=false&sort=updated.desc&limit=30" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/closare_tendering/tenders`

Upload a tender file

Multipart form: `file` (xlsx, xlsm, xlsb, xls, ods, csv, tsv or txt), optional `name` and `counterpartyCompanyId` (a CRM company). An `Idempotency-Key` header makes a repeated request return the first tender.

**Tags:** Tendering

**Requires authentication.**

### Responses

**202** – The tender, its queued read, and earlier tenders with the same file

Content-Type: `application/json`

**400** – Not a spreadsheet the reader handles, an unknown company, or a malformed form

Content-Type: `application/json`

**403** – Tendering is not enabled for the organization, or closare_tendering.manage is missing

Content-Type: `application/json`

**413** – The file is above the size the reader accepts, or the storage quota is spent

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_tendering/tenders" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/closare_tendering/tenders/{id}`

Delete a tender

Deletes the tender with its reads, lanes and files. Its Operation stays, closed.

**Tags:** Tendering

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "updatedAt": "string"
}
```

### Responses

**200** – The deleted tender

Content-Type: `application/json`

**403** – Tendering is not enabled for the organization, or closare_tendering.manage is missing

Content-Type: `application/json`

**404** – No such tender in this organization

Content-Type: `application/json`

**409** – The tender changed since it was read

Content-Type: `application/json`

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/closare_tendering/tenders/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"updatedAt\": \"string\"
}"
```

## GET `/closare_tendering/tenders/{id}`

Read a tender

**Tags:** Tendering

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – The tender, its current read with what it found, and the filed read

Content-Type: `application/json`

**403** – Tendering is not enabled for the organization, or closare_tendering.view is missing

Content-Type: `application/json`

**404** – No such tender in this organization

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_tendering/tenders/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PATCH `/closare_tendering/tenders/{id}`

Edit a tender

An absent field stays and `null` clears it. `deadlineFromFile` and `validityFromFile` take the dates the file states from the read the tender shows. `archived` archives or restores it. `adminUserId` hands the tender to another member (a user of the organization who may view tenders).

**Tags:** Tendering

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "updatedAt": "string",
  "counterpartyCompanyId": null,
  "deadline": null,
  "validFrom": null,
  "validUntil": null,
  "round": null,
  "notes": null
}
```

### Responses

**200** – The edited tender

Content-Type: `application/json`

**400** – A malformed field, an unknown company, an administrator who is not a member, or a contract period that ends before it starts

Content-Type: `application/json`

**403** – Tendering is not enabled for the organization, or closare_tendering.manage is missing

Content-Type: `application/json`

**404** – No such tender in this organization

Content-Type: `application/json`

**409** – The tender changed since it was read, or the file states no such date

Content-Type: `application/json`

### Example

```bash
curl -X PATCH "https://demo-carrier.closare.com/api/closare_tendering/tenders/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"updatedAt\": \"string\",
  \"counterpartyCompanyId\": null,
  \"deadline\": null,
  \"validFrom\": null,
  \"validUntil\": null,
  \"round\": null,
  \"notes\": null
}"
```

## PATCH `/closare_tendering/tenders/{id}/column-config`

Change the roles of a filed tender's columns

**Tags:** Tendering

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "columnConfig": [
    {
      "key": "string",
      "role": "fillin"
    }
  ],
  "updatedAt": "string"
}
```

### Responses

**200** – The tender; its reads now return the columns with these roles

Content-Type: `application/json`

**400** – A column key the filed read does not have

Content-Type: `application/json`

**403** – Tendering is not enabled for the organization, or closare_tendering.manage is missing

Content-Type: `application/json`

**404** – No such tender in this organization

Content-Type: `application/json`

**409** – The tender changed since it was read, or it was never filed

Content-Type: `application/json`

### Example

```bash
curl -X PATCH "https://demo-carrier.closare.com/api/closare_tendering/tenders/string/column-config" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"columnConfig\": [
    {
      \"key\": \"string\",
      \"role\": \"fillin\"
    }
  ],
  \"updatedAt\": \"string\"
}"
```

## POST `/closare_tendering/tenders/{id}/confirm`

File a tender's read

**Tags:** Tendering

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "parseRunId": "string",
  "updatedAt": "string"
}
```

### Responses

**200** – The filed tender; its columns are the run's, with the roles it already carried and then those given, and the run's rules become its own

Content-Type: `application/json`

**400** – A column key the run does not have

Content-Type: `application/json`

**403** – Tendering is not enabled for the organization, or closare_tendering.manage is missing

Content-Type: `application/json`

**404** – No such tender in this organization

Content-Type: `application/json`

**409** – The tender changed since it was read, or the run is not its current, finished read with lanes

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_tendering/tenders/string/confirm" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"parseRunId\": \"string\",
  \"updatedAt\": \"string\"
}"
```

## POST `/closare_tendering/tenders/{id}/current-run`

Make one of a tender's reads current

**Tags:** Tendering

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "runId": "string",
  "updatedAt": "string"
}
```

### Responses

**200** – The tender, under review with the read chosen; a filed tender stays filed with its filed read until another is filed

Content-Type: `application/json`

**403** – Tendering is not enabled for the organization, or closare_tendering.manage is missing

Content-Type: `application/json`

**404** – No such tender, or no such read of it

Content-Type: `application/json`

**409** – The tender changed since it was read, is archived, or the read has not finished

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_tendering/tenders/string/current-run" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"runId\": \"string\",
  \"updatedAt\": \"string\"
}"
```

## GET `/closare_tendering/tenders/{id}/distance`

Read a tender's distances

**Tags:** Tendering

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| unresolvedOnly | query | any | Optional |

### Responses

**200** – `{ filed, parseRunId, plan, versions, latestRun, appliedRun, kmColumns, manualCount, places: { items, total, page, pageSize }, overridesNotApplied }`. `latestRun.stale` is true for a running run with no heartbeat for 10 minutes. Places are those of the filed read as the last successful run resolved them; `unresolvedOnly=true` keeps those without a point

Content-Type: `application/json`

**400** – An unknown query parameter

Content-Type: `application/json`

**403** – Tendering is not enabled for the organization, or closare_tendering.view is missing

Content-Type: `application/json`

**404** – No such tender in this organization

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_tendering/tenders/string/distance?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/closare_tendering/tenders/{id}/distance/plan`

Save a tender's distance plan

A patch on `basedOnVersion`: listed place entries replace that place's entry and `auto` removes it; a given basis replaces the basis. Or `restoreVersion` alone, which copies that version. Each save is a new version, and its run starts at once (a queued run is re-pointed).

**Tags:** Tendering

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "basedOnVersion": 1
}
```

### Responses

**200** – `{ version, distanceRunId, keptUserEdits }`

Content-Type: `application/json`

**400** – `invalidPlan` with the `path` and `rule` of the entry that broke it; `planTooLarge` (over 2,000 entries) or `tooManyQueries` (over 200 address queries in one save)

Content-Type: `application/json`

**403** – Tendering is not enabled for the organization, or closare_tendering.price or closare_tendering.view is missing

Content-Type: `application/json`

**404** – No such tender, or no such plan version to restore, in this organization

Content-Type: `application/json`

**409** – `stalePlan` (with the current `plan`), `notFiled`, `archived` or `sentTender`

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_tendering/tenders/string/distance/plan" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"basedOnVersion\": 1
}"
```

## POST `/closare_tendering/tenders/{id}/distance/runs`

Run a tender's distance plan again

**Tags:** Tendering

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – `{ distanceRunId }`: the queued run re-pointed, or a new one; a stale running run is taken over when it is claimed

Content-Type: `application/json`

**403** – Tendering is not enabled for the organization, or closare_tendering.price or closare_tendering.view is missing

Content-Type: `application/json`

**404** – No such tender in this organization

Content-Type: `application/json`

**409** – `notFiled`, `archived`, `sentTender`, or `runActive`: a run is working with a fresh heartbeat

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_tendering/tenders/string/distance/runs" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## GET `/closare_tendering/tenders/{id}/distance/runs/{runId}`

Read a tender distance run

**Tags:** Tendering

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| runId | path | any | Required |

### Responses

**200** – `{ id, status, stale, planVersion, errorCode, report? }`; `report` once the run succeeded. Status is `queued`, `running`, `succeeded`, `failed` or `superseded`

Content-Type: `application/json`

**403** – Tendering is not enabled for the organization, or closare_tendering.view is missing

Content-Type: `application/json`

**404** – No such tender, or no such run of it, in this organization

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_tendering/tenders/string/distance/runs/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_tendering/tenders/{id}/lanes`

List a tender's lanes

**Tags:** Tendering

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| runId | query | any | Optional |
| sheet | query | any | Optional |
| equipment | query | any | Optional |
| originCountry | query | any | Optional |
| destinationCountry | query | any | Optional |
| search | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| assignee | query | any | Optional |
| groupBy | query | any | Optional |
| page | query | any | Optional |
| pageSize | query | any | Optional |

### Responses

**200** – `{ items, page, pageSize, total, totalPages, runId }`; empty while no run has read the file. Each item has `assignees` (`{ id, name }`: who prices it). `assignee` keeps one person's lanes (a user id, `unassigned`, or `me`); `groupBy=assignee` adds `groups` (`{ key, userId, name, lanes }`, busiest first, unassigned last) and a `group` key on each item, a lane appearing once per person, and `total` counts those rows. Lanes of the read the tender shows have `answers`: each to-fill column answerable on the lane, with its answer (`{ value, updatedAt }`) or null. Each lane has `distance`: on the filed read `{ km, kmSource, reason, countryKm, precision, deviation, placeFingerprint, override }` (`kmSource` is `file`, `road`, `estimate`, `manual` or null), else `{ state: 'not_filed' }`

Content-Type: `application/json`

**400** – An unknown filter or sort

Content-Type: `application/json`

**403** – Tendering is not enabled for the organization, or closare_tendering.view is missing

Content-Type: `application/json`

**404** – No such tender, or no such run of it, in this organization

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_tendering/tenders/string/lanes?sortField=ordinal&sortDir=asc&page=1&pageSize=100" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/closare_tendering/tenders/{id}/lanes/{laneId}/answers`

Answer a to-fill cell of a lane

The answer belongs to the workbook cell the lane's row has in that column, so every lane of the row shares it. An empty value clears the cell. `updatedAt` is the answer's version as read (null for a cell with no answer).

**Tags:** Tendering

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| laneId | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "columnKey": "string",
  "value": "string",
  "updatedAt": null
}
```

### Responses

**200** – `{ laneId, columnKey, cell: { sheet, row, col }, answer: { value, updatedAt } | null }`

Content-Type: `application/json`

**400** – A column that is not a to-fill cell of this lane, a value outside the file's list, or a value longer than 500 characters

Content-Type: `application/json`

**403** – Tendering is not enabled for the organization, or closare_tendering.manage is missing

Content-Type: `application/json`

**404** – No such tender, or no such lane of it, in this organization

Content-Type: `application/json`

**409** – `answerConflict`: the cell changed since it was read (`answer` is the current one); `notShownRead`: the lane is not of the read the tender shows; `archived`

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/closare_tendering/tenders/string/lanes/string/answers" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"columnKey\": \"string\",
  \"value\": \"string\",
  \"updatedAt\": null
}"
```

## GET `/closare_tendering/tenders/{id}/lanes/{laneId}/distance`

Read a lane's route for its map

The lane's two places as the latest successful distance run put them, and the road between them from the maps cache, as `[lat, lng]` points. A road kept before lines were is looked up once (one routing transaction) when the reader holds closare_tendering.price; for anyone else it reads `not_looked_up`.

**Tags:** Tendering

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| laneId | path | any | Required |

### Responses

**200** – `{ route: { origin, destination, line, missing } }`: each place `{ label, point, precision }` or null; `line` null with `missing` = `no_run`, `no_point`, `not_looked_up`, `no_line`, `same_point`, `no_route`, `unconfigured`, `unavailable`, `ceiling`, `lookups_off` or `rate_limited`

Content-Type: `application/json`

**403** – Tendering is not enabled for the organization, or closare_tendering.view is missing

Content-Type: `application/json`

**404** – No such tender, or no such lane of it, in this organization

Content-Type: `application/json`

**409** – `notFiled`, or `notFiledRead`: the lane is not of the filed read

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_tendering/tenders/string/lanes/string/distance" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/closare_tendering/tenders/{id}/lanes/{laneId}/distance`

Type a lane's km by hand

The km applies while the lane keeps its two places; after a re-read that changes them it is listed as not applied. `updatedAt` is the km's own version as read (null when the lane had none); passing an existing one replaces it even when it no longer applies. `km: null` clears it.

**Tags:** Tendering

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| laneId | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "km": null,
  "updatedAt": null
}
```

### Responses

**200** – `{ distance }`: the lane's effective km, source and road split

Content-Type: `application/json`

**400** – A km at or below 0, above 20,000, or with more than one decimal

Content-Type: `application/json`

**403** – Tendering is not enabled for the organization, or closare_tendering.price or closare_tendering.view is missing

Content-Type: `application/json`

**404** – No such tender, or no such lane of it, in this organization

Content-Type: `application/json`

**409** – `laneDistanceConflict` (with the current `override`), `notFiledRead`: the lane is not of the filed read, `notFiled`, `archived` or `sentTender`

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/closare_tendering/tenders/string/lanes/string/distance" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"km\": null,
  \"updatedAt\": null
}"
```

## GET `/closare_tendering/tenders/{id}/overview`

Read a tender's overview

**Tags:** Tendering

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – `{ run, sheets, columns, facets, gridsKept, team }` for the filed run (or, in a reopened review, its newer read once it finished), else the current read once it finished, else the latest read that did; `run` is null while none did. `team` is who is responsible for it: `{ admin, read, laneTotal, people, unassigned, hasRules }`, people with lanes busiest first (`{ id, name, former, lanes }`)

Content-Type: `application/json`

**403** – Tendering is not enabled for the organization, or closare_tendering.view is missing

Content-Type: `application/json`

**404** – No such tender in this organization

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_tendering/tenders/string/overview" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_tendering/tenders/{id}/parse-runs`

List a tender's reads

**Tags:** Tendering

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – The reads, newest first (at most 100)

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "seq": 1,
      "trigger": "string",
      "basedOnRunId": null,
      "status": "string",
      "laneCount": null,
      "reconciliationStatus": null,
      "current": true,
      "filed": true,
      "author": null,
      "createdAt": "string"
    }
  ]
}
```

**403** – Tendering is not enabled for the organization, or closare_tendering.view is missing

Content-Type: `application/json`

**404** – No such tender in this organization

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_tendering/tenders/string/parse-runs" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/closare_tendering/tenders/{id}/parse-runs`

Read a tender's original again, or with a fix

**Tags:** Tendering

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**202** – The tender and its new queued read. The read starts from the base read's rules (default: the current read), with the rule patch and the answers merged over them. A filed tender reopens its review; its filed read stays in force until another is filed

Content-Type: `application/json`

**400** – The answers or rules are not valid, or merged they exceed 64 KB

Content-Type: `application/json`

**403** – Tendering is not enabled for the organization, or closare_tendering.manage is missing

Content-Type: `application/json`

**404** – No such tender, or no such base read of it

Content-Type: `application/json`

**409** – The tender is archived

Content-Type: `application/json`

**413** – The body exceeds 64 KB

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_tendering/tenders/string/parse-runs" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## POST `/closare_tendering/tenders/{id}/review`

Reopen or cancel a filed tender's review

**Tags:** Tendering

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "action": "reopen",
  "updatedAt": "string"
}
```

### Responses

**200** – The tender: reopened under review on its filed read, or back to filed with its filed read current

Content-Type: `application/json`

**403** – Tendering is not enabled for the organization, or closare_tendering.manage is missing

Content-Type: `application/json`

**404** – No such tender in this organization

Content-Type: `application/json`

**409** – The tender changed since it was read, is archived, was never filed, or is already in the state asked for

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_tendering/tenders/string/review" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"action\": \"reopen\",
  \"updatedAt\": \"string\"
}"
```

## GET `/closare_tendering/tenders/{id}/source`

Download a tender's original file

**Tags:** Tendering

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – The file's bytes

Content-Type: `application/json`

**403** – Tendering is not enabled for the organization, or closare_tendering.view is missing

Content-Type: `application/json`

**404** – No such tender, or its file, in this organization

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_tendering/tenders/string/source" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_tendering/tenders/{id}/team`

Read who is responsible for a tender

**Tags:** Tendering

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – `{ admin, read, runId, laneTotal, people, unassigned, hasRules, homeCountry, tenderRules, canManage, canEditSettings }`: the administrator and every person a rule names (`{ id, name, former, lanes, rules }`), busiest first, for the run the tender shows; `tenderRules` is the tender's own set (`{ rules, updatedAt }`). With closare_tendering.manage also `members`, `equipmentTypes` and `countryCodes`

Content-Type: `application/json`

**403** – Tendering is not enabled for the organization, or closare_tendering.view is missing

Content-Type: `application/json`

**404** – No such tender in this organization

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_tendering/tenders/string/team" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_tendering/tenders/{id}/workbook`

Read a window of a tender's workbook

**Tags:** Tendering

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| sheet | query | any | Optional |
| offset | query | any | Optional |
| limit | query | any | Optional |

### Responses

**200** – `{ runId, gridsKept, sheets, sheet }`: every sheet with its job, and `sheet` the rows `offset`…`offset + limit` of the asked sheet (the first to price by default), with its header row, answer column, columns to fill and lane rows

Content-Type: `application/json`

**400** – An unknown parameter, or a window out of bounds

Content-Type: `application/json`

**403** – Tendering is not enabled for the organization, or closare_tendering.view is missing

Content-Type: `application/json`

**404** – No such tender in this organization, or no such sheet in its workbook

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_tendering/tenders/string/workbook?offset=0&limit=200" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_work/approval-tasks/{id}`

Read a persisted approval task and its source decision

**Tags:** Closare Work

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Task projection, activity and authorized source approval

Content-Type: `application/json`

**404** – Task or source not accessible

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_work/approval-tasks/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_work/case`

List scoped coordination cases

**Tags:** Closare Work

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| cursor | query | any | Optional |
| limit | query | any | Optional |
| status | query | any | Optional |
| type | query | any | Optional |
| ownerUserId | query | any | Optional |
| operationId | query | any | Optional |
| needsAttention | query | any | Optional |

### Responses

**200** – items, nextCursor and canManage

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_work/case?limit=30" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/closare_work/case`

Open a coordination case, with or without an operation

**Tags:** Closare Work

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "clientRequestId": "00000000-0000-4000-8000-000000000000",
  "type": "string",
  "title": null,
  "summary": null,
  "operationId": null,
  "ownerUserId": null,
  "subjectContactId": null,
  "data": {},
  "originTurnId": null
}
```

### Responses

**201** – id, operationId, version, updatedAt, replayed

Content-Type: `application/json`

**404** – Linked operation unavailable

Content-Type: `application/json`

**409** – Request replay conflict

Content-Type: `application/json`

**503** – Encryption unavailable

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_work/case" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"clientRequestId\": \"00000000-0000-4000-8000-000000000000\",
  \"type\": \"string\",
  \"title\": null,
  \"summary\": null,
  \"operationId\": null,
  \"ownerUserId\": null,
  \"subjectContactId\": null,
  \"data\": {},
  \"originTurnId\": null
}"
```

## GET `/closare_work/case/{id}`

Read a coordination case and its merged state

**Tags:** Closare Work

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Scoped case detail and canManage

Content-Type: `application/json`

**404** – Case unavailable

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_work/case/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PATCH `/closare_work/case/{id}`

Apply one explicit versioned case transition

**Tags:** Closare Work

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "clientRequestId": "00000000-0000-4000-8000-000000000000",
  "expectedVersion": 1,
  "transition": "update",
  "title": null,
  "summary": null,
  "ownerUserId": null,
  "subjectContactId": null
}
```

### Responses

**200** – id, operationId, version, updatedAt, replayed

Content-Type: `application/json`

**409** – Stale version, closed case, already-linked operation or stale attention

Content-Type: `application/json`

### Example

```bash
curl -X PATCH "https://demo-carrier.closare.com/api/closare_work/case/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"clientRequestId\": \"00000000-0000-4000-8000-000000000000\",
  \"expectedVersion\": 1,
  \"transition\": \"update\",
  \"title\": null,
  \"summary\": null,
  \"ownerUserId\": null,
  \"subjectContactId\": null
}"
```

## GET `/closare_work/case/{id}/activity`

Read the ordered case transition timeline

**Tags:** Closare Work

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| cursor | query | any | Optional |
| limit | query | any | Optional |

### Responses

**200** – items and nextCursor

Content-Type: `application/json`

**404** – Case unavailable

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_work/case/:id/activity?limit=30" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_work/operation`

List scoped operations with keyset pagination

**Tags:** Closare Work

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| cursor | query | any | Optional |
| limit | query | any | Optional |
| kind | query | any | Optional |
| status | query | any | Optional |
| ownerIdentityId | query | any | Optional |

### Responses

**200** – items and nextCursor

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_work/operation?limit=30" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/closare_work/operation`

Register an authorized existing external record

**Tags:** Closare Work

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "clientRequestId": "00000000-0000-4000-8000-000000000000",
  "sourceId": "string",
  "externalId": "string"
}
```

### Responses

**201** – id, operationId, version, updatedAt, replayed

Content-Type: `application/json`

**409** – Identity or request conflict

Content-Type: `application/json`

**503** – Source or encryption unavailable

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_work/operation" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"clientRequestId\": \"00000000-0000-4000-8000-000000000000\",
  \"sourceId\": \"string\",
  \"externalId\": \"string\"
}"
```

## GET `/closare_work/operation-presentation`

List operations using the trusted tenant presentation mapping

**Tags:** Closare Work

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| kind | query | any | Optional |
| sort | query | any | Optional. Profile sort ID and direction, e.g. label.asc |
| cursor | query | any | Optional |
| limit | query | any | Optional |

### Responses

**200** – Availability or resolved category, filters, sorts, items and cursor

Content-Type: `application/json`

**400** – Invalid category, filters, sort or scoped cursor

Content-Type: `application/json`

**403** – Scope or Work view permission denied

Content-Type: `application/json`

**503** – Encryption, aggregate validation or bounded presentation capacity unavailable

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_work/operation-presentation" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_work/operation/{id}`

Read one scoped operation and bounded active references

**Tags:** Closare Work

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Operation with typed data, canonical detail url, owner display, refs and capabilities

Content-Type: `application/json`

**404** – Scoped operation not found

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_work/operation/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_work/operation/{id}/action`

List scoped business actions

**Tags:** Closare Work

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| cursor | query | any | Optional |
| limit | query | any | Optional |
| status | query | any | Optional |

### Responses

**200** – items (each with lastRunStatus), nextCursor and canManage

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_work/operation/:id/action?limit=30" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/closare_work/operation/{id}/action`

Create or reuse an active operation concern

**Tags:** Closare Work

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "clientRequestId": "00000000-0000-4000-8000-000000000000",
  "kind": "string",
  "title": "string",
  "objective": "string",
  "dedupeKey": "string",
  "priority": "NORMAL",
  "dueAt": null,
  "expiresAt": null,
  "data": {},
  "evidenceRefs": []
}
```

### Responses

**201** – id, operationId, version, updatedAt, replayed

Content-Type: `application/json`

**409** – Request or concern conflict

Content-Type: `application/json`

**503** – Encryption unavailable

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_work/operation/:id/action" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"clientRequestId\": \"00000000-0000-4000-8000-000000000000\",
  \"kind\": \"string\",
  \"title\": \"string\",
  \"objective\": \"string\",
  \"dedupeKey\": \"string\",
  \"priority\": \"NORMAL\",
  \"dueAt\": null,
  \"expiresAt\": null,
  \"data\": {},
  \"evidenceRefs\": []
}"
```

## GET `/closare_work/operation/{id}/action/{actionId}`

Read an operation action and its outcome

**Tags:** Closare Work

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| actionId | path | any | Required |

### Responses

**200** – Scoped action detail and canManage

Content-Type: `application/json`

**404** – Action unavailable

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_work/operation/:id/action/:actionId" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PATCH `/closare_work/operation/{id}/action/{actionId}`

Apply an explicit versioned manual action transition

**Tags:** Closare Work

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| actionId | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "clientRequestId": "00000000-0000-4000-8000-000000000000",
  "expectedVersion": 1,
  "transition": "update",
  "dueAt": null
}
```

### Responses

**200** – id, operationId, version, updatedAt, replayed

Content-Type: `application/json`

**409** – Stale version, terminal action or replay conflict

Content-Type: `application/json`

### Example

```bash
curl -X PATCH "https://demo-carrier.closare.com/api/closare_work/operation/:id/action/:actionId" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"clientRequestId\": \"00000000-0000-4000-8000-000000000000\",
  \"expectedVersion\": 1,
  \"transition\": \"update\",
  \"dueAt\": null
}"
```

## GET `/closare_work/operation/{id}/action/{actionId}/activity`

Read immutable operation action history

**Tags:** Closare Work

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| actionId | path | any | Required |
| cursor | query | any | Optional |
| limit | query | any | Optional |

### Responses

**200** – items and nextCursor

Content-Type: `application/json`

**404** – Action or cursor unavailable

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_work/operation/:id/action/:actionId/activity?limit=30" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_work/operation/{id}/action/{actionId}/run`

List recent scoped Action runs and current run capability

**Tags:** Closare Work

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| actionId | path | any | Required |

### Responses

**200** – items (latest 20), canRun and runtimeAvailable

Content-Type: `application/json`

**503** – Runtime service unavailable

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_work/operation/:id/action/:actionId/run" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/closare_work/operation/{id}/action/{actionId}/run`

Request a durable versioned Cowork Action run

**Tags:** Closare Work

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| actionId | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "clientRequestId": "00000000-0000-4000-8000-000000000000",
  "expectedVersion": 1
}
```

### Responses

**202** – Durable Action run receipt, not business completion

Content-Type: `application/json`

**409** – Stale Action version or request conflict

Content-Type: `application/json`

**503** – Runtime unavailable

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_work/operation/:id/action/:actionId/run" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"clientRequestId\": \"00000000-0000-4000-8000-000000000000\",
  \"expectedVersion\": 1
}"
```

## GET `/closare_work/operation/{id}/input`

Read scoped operation input page

**Tags:** Closare Work

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| cursor | query | any | Optional |
| limit | query | any | Optional |

### Responses

**200** – items and nextCursor

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_work/operation/:id/input?limit=30" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/closare_work/operation/{id}/input`

Apply guarded operation input.attach

**Tags:** Closare Work

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "clientRequestId": "00000000-0000-4000-8000-000000000000",
  "idempotencyKey": "string",
  "kind": "string",
  "sourceKind": "string",
  "sourceId": "string",
  "reason": null,
  "occurredAt": "string"
}
```

### Responses

**200** – id, operationId, version, updatedAt, replayed

Content-Type: `application/json`

**409** – State or idempotency conflict

Content-Type: `application/json`

**503** – Required capability unavailable

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_work/operation/:id/input" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"clientRequestId\": \"00000000-0000-4000-8000-000000000000\",
  \"idempotencyKey\": \"string\",
  \"kind\": \"string\",
  \"sourceKind\": \"string\",
  \"sourceId\": \"string\",
  \"reason\": null,
  \"occurredAt\": \"string\"
}"
```

## GET `/closare_work/operation/{id}/observation`

Read scoped operation observation page

**Tags:** Closare Work

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| cursor | query | any | Optional |
| limit | query | any | Optional |

### Responses

**200** – items and nextCursor

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_work/operation/:id/observation?limit=30" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/closare_work/operation/{id}/observation`

Apply guarded operation observation.record

**Tags:** Closare Work

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "clientRequestId": "00000000-0000-4000-8000-000000000000",
  "idempotencyKey": "string",
  "observationType": "general",
  "category": "ASSESSMENT",
  "summary": "string",
  "occurredAt": "string",
  "inputIds": []
}
```

### Responses

**200** – id, operationId, version, updatedAt, replayed

Content-Type: `application/json`

**409** – State or idempotency conflict

Content-Type: `application/json`

**503** – Required capability unavailable

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_work/operation/:id/observation" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"clientRequestId\": \"00000000-0000-4000-8000-000000000000\",
  \"idempotencyKey\": \"string\",
  \"observationType\": \"general\",
  \"category\": \"ASSESSMENT\",
  \"summary\": \"string\",
  \"occurredAt\": \"string\",
  \"inputIds\": []
}"
```

## GET `/closare_work/operation/{id}/observation/{observationId}`

Read an exact scoped Operation observation and its evidence

**Tags:** Closare Work

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| observationId | path | any | Required |

### Responses

**200** – Observation and authorized input metadata

Content-Type: `application/json`

**404** – Operation or observation unavailable

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_work/operation/:id/observation/:observationId" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_work/operation/{id}/participant`

Read scoped operation participant page

**Tags:** Closare Work

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| cursor | query | any | Optional |
| limit | query | any | Optional |

### Responses

**200** – items and nextCursor

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_work/operation/:id/participant?limit=30" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_work/operation/{id}/state`

Read scoped operation state page

**Tags:** Closare Work

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| cursor | query | any | Optional |
| limit | query | any | Optional |

### Responses

**200** – items and nextCursor

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_work/operation/:id/state?limit=30" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/closare_work/operation/{id}/state`

Apply guarded operation state.write

**Tags:** Closare Work

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "clientRequestId": "00000000-0000-4000-8000-000000000000",
  "expectedVersion": 1,
  "key": "string",
  "content": "string",
  "schemaVersion": null
}
```

### Responses

**200** – id, operationId, version, updatedAt, replayed

Content-Type: `application/json`

**409** – State or idempotency conflict

Content-Type: `application/json`

**503** – Required capability unavailable

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_work/operation/:id/state" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"clientRequestId\": \"00000000-0000-4000-8000-000000000000\",
  \"expectedVersion\": 1,
  \"key\": \"string\",
  \"content\": \"string\",
  \"schemaVersion\": null
}"
```

## GET `/closare_work/owner`

List scoped operation owner display options

**Tags:** Closare Work

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| cursor | query | any | Optional |
| limit | query | any | Optional |

### Responses

**200** – items: id/label, nextCursor

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_work/owner?limit=30" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_work/source`

List entitled operation source adapters

**Tags:** Closare Work

**Requires authentication.**

### Responses

**200** – items: id/label options (labelKey when the label is translated), canManage

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_work/source" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_work/task`

List the operator task board page, state counts and assignee options

**Tags:** Closare Work

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| state | query | any | Optional |
| kind | query | any | Optional |
| assigneeUserId | query | any | Optional |
| search | query | any | Optional |
| sortDir | query | any | Optional |

### Responses

**200** – items (each operation carries its canonical detail url), page, total, counts, members and canManage

Content-Type: `application/json`

**403** – Scope or Work view permission denied

Content-Type: `application/json`

**413** – Too many tasks in scope to search after decryption

Content-Type: `application/json`

**503** – Encryption unavailable

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_work/task?page=1&pageSize=25&state=pending&sortDir=asc" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/closare_work/task/{id}`

Read one task with its evidence, proposed case and history

**Tags:** Closare Work

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Task detail, assignee options and canManage

Content-Type: `application/json`

**404** – Task unavailable

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/closare_work/task/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/closare_work/task/{id}`

Apply one versioned operator command to a task

**Tags:** Closare Work

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "expectedVersion": 1,
  "intent": "snooze",
  "snoozedUntil": "string"
}
```

### Responses

**200** – outcome, version and the resulting caseId when promoted

Content-Type: `application/json`

**403** – Task manage permission denied

Content-Type: `application/json`

**404** – Task, actor or assignee not in scope

Content-Type: `application/json`

**409** – Stale version, inactive task, or a state the command does not apply to

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/closare_work/task/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"expectedVersion\": 1,
  \"intent\": \"snooze\",
  \"snoozedUntil\": \"string\"
}"
```

## DELETE `/communication_channels/admin/channels/{id}`

Admin delete (soft-delete) a tenant-wide communication channel

**Tags:** CommunicationChannels

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**204** – Channel deleted

**400** – Invalid channel id

Content-Type: `application/json`

**401** – Unauthorized

Content-Type: `application/json`

**404** – Channel not found or not a tenant-wide channel

Content-Type: `application/json`

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/communication_channels/admin/channels/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/communication_channels/channels`

List communication channels for the current tenant

**Tags:** CommunicationChannels

**Requires authentication.**

### Responses

**200** – Channel list (paginated)

Content-Type: `application/json`

**400** – Invalid query parameters

Content-Type: `application/json`

**401** – Unauthorized

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/communication_channels/channels" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/communication_channels/channels/{id}`

DELETE /communication_channels/channels/{id}

**Tags:** Communication Channels

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**204** – Success

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/communication_channels/channels/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/communication_channels/channels/{id}`

Get a single communication channel by id

**Tags:** CommunicationChannels

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Channel detail

Content-Type: `application/json`

**400** – Invalid channel id

Content-Type: `application/json`

**401** – Unauthorized

Content-Type: `application/json`

**404** – Channel not found

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/communication_channels/channels/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/communication_channels/channels/{id}/health`

Snapshot of channel delivery health (last 24h)

**Tags:** CommunicationChannels

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Health snapshot

Content-Type: `application/json`

**400** – Invalid channel id

Content-Type: `application/json`

**401** – Unauthorized

Content-Type: `application/json`

**404** – Channel not found

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/communication_channels/channels/:id/health" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/communication_channels/channels/{id}/import-history`

Queue a backlog import for a channel (Spec B § Phase B6)

**Tags:** CommunicationChannels

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "sinceDays": 30,
  "maxMessages": 1000
}
```

### Responses

**202** – Import job queued; returns { progressJobId }

Content-Type: `application/json`

**400** – Invalid channel id or unsupported provider

Content-Type: `application/json`

**401** – Unauthorized

Content-Type: `application/json`

**404** – Channel not found / not accessible

Content-Type: `application/json`

**409** – Channel is not connected (requires reauth / error)

Content-Type: `application/json`

**429** – Another import is already running for this channel

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/communication_channels/channels/:id/import-history" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"sinceDays\": 30,
  \"maxMessages\": 1000
}"
```

## POST `/communication_channels/channels/{id}/poll-now`

Manually trigger a poll cycle for a channel (demo / operator override)

**Tags:** CommunicationChannels

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**202** – Poll job enqueued

Content-Type: `application/json`

**400** – Invalid channel id

Content-Type: `application/json`

**401** – Unauthorized

Content-Type: `application/json`

**404** – Channel not found

Content-Type: `application/json`

**409** – Channel disabled, not connected, or push-driven (never polled)

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/communication_channels/channels/:id/poll-now" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/communication_channels/channels/{id}/push/register`

Force-register push delivery for a channel (Spec C § Phase C5)

**Tags:** CommunicationChannels

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**202** – Push registration attempted; check result.pushStatus

Content-Type: `application/json`

**400** – Invalid id or unsupported provider

Content-Type: `application/json`

**401** – Unauthorized

Content-Type: `application/json`

**403** – Missing push.manage feature

Content-Type: `application/json`

**404** – Channel not found

Content-Type: `application/json`

**409** – Provider does not support push (IMAP)

Content-Type: `application/json`

**502** – Provider returned an error during registration

Content-Type: `application/json`

**503** – Webhook base URL or Pub/Sub topic not configured

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/communication_channels/channels/:id/push/register" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/communication_channels/channels/{id}/set-primary`

Mark a per-user channel as primary

**Tags:** CommunicationChannels

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Channel set as primary (or already primary)

Content-Type: `application/json`

**400** – Invalid channel id

Content-Type: `application/json`

**401** – Unauthorized

Content-Type: `application/json`

**404** – Channel not found or not owned by current user

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/communication_channels/channels/:id/set-primary" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/communication_channels/channels/{id}/test-send`

Diagnostic — send a test message through the channel without persisting

**Tags:** CommunicationChannels

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Test send result

Content-Type: `application/json`

**400** – Invalid channel id

Content-Type: `application/json`

**401** – Unauthorized

Content-Type: `application/json`

**403** – Not allowed to manage this channel

Content-Type: `application/json`

**404** – Channel or adapter not found

Content-Type: `application/json`

**409** – Channel not connected

Content-Type: `application/json`

**422** – Invalid request body

Content-Type: `application/json`

**502** – Provider error

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/communication_channels/channels/:id/test-send" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/communication_channels/channels/connect/credentials`

Connect a credential-based per-user channel (IMAP/SMTP)

**Tags:** CommunicationChannels

**Requires authentication.**

### Responses

**201** – Channel connected

Content-Type: `application/json`

**401** – Unauthorized

Content-Type: `application/json`

**403** – Provider is tenant-scoped — use the tenant connect route

Content-Type: `application/json`

**404** – Unknown provider

Content-Type: `application/json`

**409** – Mailbox already connected via another provider

Content-Type: `application/json`

**422** – Invalid body or credential validation failed

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/communication_channels/channels/connect/credentials" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/communication_channels/channels/connect/tenant-credentials`

Connect a tenant-wide credential-based channel (push: FCM/APNs/Expo)

**Tags:** CommunicationChannels

**Requires authentication.**

### Responses

**201** – Channel connected

Content-Type: `application/json`

**400** – Provider is not tenant-scoped

Content-Type: `application/json`

**401** – Unauthorized

Content-Type: `application/json`

**404** – Unknown provider

Content-Type: `application/json`

**422** – Invalid body or credential validation failed

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/communication_channels/channels/connect/tenant-credentials" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/communication_channels/me/channels`

List the current user's connected channels

**Tags:** CommunicationChannels

**Requires authentication.**

### Responses

**200** – List of user-owned channels

Content-Type: `application/json`

**401** – Unauthorized

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/communication_channels/me/channels" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/communication_channels/messages/{messageId}/reactions`

Add a reaction to a channel-linked message

**Tags:** CommunicationChannels

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| messageId | path | any | Required |

### Responses

**201** – Reaction added

Content-Type: `application/json`

**400** – Invalid messageId

Content-Type: `application/json`

**401** – Unauthorized

Content-Type: `application/json`

**403** – Channel is owned by another user

Content-Type: `application/json`

**409** – Message not channel-linked or duplicate reaction

Content-Type: `application/json`

**422** – Invalid request body

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/communication_channels/messages/:messageId/reactions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/communication_channels/messages/{messageId}/reactions/{reactionId}`

Remove a reaction from a channel-linked message

**Tags:** CommunicationChannels

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| messageId | path | any | Required |
| reactionId | path | any | Required |

### Responses

**204** – Reaction removed

**400** – Invalid params

Content-Type: `application/json`

**401** – Unauthorized

Content-Type: `application/json`

**403** – Channel is owned by another user

Content-Type: `application/json`

**404** – Reaction not found or not owned by current user

Content-Type: `application/json`

**409** – Message not channel-linked

Content-Type: `application/json`

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/communication_channels/messages/:messageId/reactions/:reactionId" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/communication_channels/oauth/{provider}/callback`

OAuth callback — exchange code, persist credentials, create per-user channel

**Tags:** CommunicationChannels

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| provider | path | any | Required |

### Responses

**200** – Success response

Content-Type: `application/json`

**302** – Redirect back to returnUrl with flash query params

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/communication_channels/oauth/:provider/callback" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/communication_channels/oauth/{provider}/initiate`

Start a per-user channel OAuth flow

**Tags:** CommunicationChannels

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| provider | path | any | Required |

### Responses

**200** – Authorize URL + state cookie set

Content-Type: `application/json`

**400** – Invalid provider or unsupported (no OAuth)

Content-Type: `application/json`

**401** – Unauthorized

Content-Type: `application/json`

**422** – Invalid request body

Content-Type: `application/json`

**502** – Adapter failed to build authorize URL

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/communication_channels/oauth/:provider/initiate" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/communication_channels/send-as-user`

Send a message through the current user's own channel

**Tags:** CommunicationChannels

**Requires authentication.**

### Responses

**202** – Message persisted; outbound delivery enqueued

Content-Type: `application/json`

**401** – Unauthorized

Content-Type: `application/json`

**403** – Cannot send through a channel you don't own

Content-Type: `application/json`

**404** – Channel not found

Content-Type: `application/json`

**409** – Channel in a non-deliverable transitional status

Content-Type: `application/json`

**422** – Invalid body, or channel requires_reauth / disconnected

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/communication_channels/send-as-user" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/communication_channels/test-seed`

Test-only: seed a connected channel or emit an inbound message (env-gated)

**Tags:** CommunicationChannels

**Requires authentication.**

### Responses

**201** – Channel seeded / inbound message emitted

Content-Type: `application/json`

**401** – Unauthorized

Content-Type: `application/json`

**404** – Test channel seeding disabled (production default), or the requested channel does not belong to the caller

Content-Type: `application/json`

**422** – Invalid request body

Content-Type: `application/json`

**500** – Seed failed

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/communication_channels/test-seed" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/communication_channels/threads/{threadId}/assign`

Reassign a channel-linked conversation to a different owner

**Tags:** CommunicationChannels

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| threadId | path | any | Required |

### Responses

**200** – Conversation reassigned (or unchanged)

Content-Type: `application/json`

**400** – Invalid threadId

Content-Type: `application/json`

**401** – Unauthorized

Content-Type: `application/json`

**404** – Conversation not channel-linked

Content-Type: `application/json`

**422** – Invalid request body

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/communication_channels/threads/:threadId/assign" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/communication_channels/webhook/{provider}`

Process an inbound channel webhook (Slack, WhatsApp, Email, ...)

**Tags:** CommunicationChannels

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| provider | path | any | Required |

### Responses

**202** – Webhook accepted for async processing

Content-Type: `application/json`

**401** – Signature verification failed against every candidate channel

Content-Type: `application/json`

**404** – Unknown provider

Content-Type: `application/json`

**413** – Webhook payload too large

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/communication_channels/webhook/:provider" \
  -H "Accept: application/json"
```

## POST `/communication_channels/webhooks/gmail`

Gmail Pub/Sub push notification webhook (Spec C § Phase C2)

**Tags:** CommunicationChannels

### Responses

**204** – Notification verified + history-sync job enqueued

**400** – Body not a valid Pub/Sub envelope

Content-Type: `application/json`

**401** – Invalid JWT or email claim

Content-Type: `application/json`

**403** – Wrong audience

Content-Type: `application/json`

**413** – Webhook payload too large

Content-Type: `application/json`

**503** – Webhook not configured / Google certs unreachable

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/communication_channels/webhooks/gmail" \
  -H "Accept: application/json"
```

## GET `/configs/cache`

Get cache statistics

Returns detailed cache statistics including total entries and breakdown by cache segments. Requires cache service to be available.

**Tags:** Configs

**Requires authentication.**

### Responses

**200** – Cache statistics

Content-Type: `application/json`

```json
{
  "generatedAt": "string",
  "totalKeys": 1,
  "segments": [
    {
      "segment": "string",
      "resource": null,
      "method": null,
      "path": null,
      "keyCount": 1,
      "keys": [
        "string"
      ]
    }
  ]
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to resolve cache stats

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**503** – Cache service unavailable

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/configs/cache" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/configs/cache`

Purge cache

Purges cache entries. Supports two actions: purgeAll (clears entire cache) or purgeSegment (clears specific segment). Returns updated cache statistics after purge.

**Tags:** Configs

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "action": "purgeAll"
}
```

### Responses

**200** – Cache segment cleared successfully

Content-Type: `application/json`

```json
{
  "action": "purgeSegment",
  "segment": "string",
  "deleted": 1,
  "stats": {
    "generatedAt": "string",
    "totalKeys": 1,
    "segments": [
      {
        "segment": "string",
        "resource": null,
        "method": null,
        "path": null,
        "keyCount": 1,
        "keys": [
          "string"
        ]
      }
    ]
  }
}
```

**400** – Invalid request - missing segment identifier for purgeSegment action

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to purge cache

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**503** – Cache service unavailable

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/configs/cache" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"action\": \"purgeAll\"
}"
```

## DELETE `/configs/module-telemetry`

Clear module telemetry data

Development-only endpoint that clears in-memory module telemetry and local process telemetry files.

**Tags:** Configs

**Requires authentication.**

### Responses

**200** – Module telemetry cleared

Content-Type: `application/json`

```json
{
  "cleared": true
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Forbidden outside development mode

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/configs/module-telemetry" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/configs/module-telemetry`

Get module resource usage telemetry

Returns in-process module resource attribution for API routes, event subscribers, and queue workers.

**Tags:** Configs

**Requires authentication.**

### Responses

**200** – Module resource usage report

Content-Type: `application/json`

```json
{
  "generatedAt": "string",
  "startedAt": "string",
  "enabled": true,
  "bucketIntervalMs": 1,
  "totals": {
    "modules": 1,
    "operations": 1,
    "calls": 1,
    "errors": 1,
    "totalDurationMs": 1,
    "totalCpuMs": 1,
    "positiveHeapDeltaBytes": 1,
    "positiveRssDeltaBytes": 1
  },
  "thresholds": {
    "p95DurationMs": 1,
    "cpuMs": 1,
    "positiveHeapDeltaBytes": 1,
    "positiveRssDeltaBytes": 1,
    "errors": 1
  },
  "modules": [
    {
      "moduleId": "string",
      "calls": 1,
      "errors": 1,
      "totalDurationMs": 1,
      "p95DurationMs": 1,
      "totalCpuMs": 1,
      "positiveHeapDeltaBytes": 1,
      "positiveRssDeltaBytes": 1,
      "surfaces": [
        {
          "surface": "api",
          "calls": 1,
          "errors": 1,
          "totalDurationMs": 1,
          "p95DurationMs": 1,
          "totalCpuMs": 1,
          "positiveHeapDeltaBytes": 1,
          "positiveRssDeltaBytes": 1
        }
      ],
      "topOperations": [
        {
          "moduleId": "string",
          "surface": "api",
          "operation": "string",
          "resourceId": null,
          "calls": 1,
          "errors": 1,
          "totalDurationMs": 1,
          "maxDurationMs": 1,
          "p95DurationMs": 1,
          "totalCpuUserMs": 1,
          "totalCpuSystemMs": 1,
          "maxCpuMs": 1,
          "totalHeapDeltaBytes": 1,
          "positiveHeapDeltaBytes": 1,
          "maxHeapDeltaBytes": 1,
          "totalRssDeltaBytes": 1,
          "positiveRssDeltaBytes": 1,
          "maxRssDeltaBytes": 1,
          "firstSeenAt": "string",
          "lastSeenAt": "string"
        }
      ],
      "candidateReasons": [
        "string"
      ]
    }
  ],
  "candidates": [
    {
      "moduleId": "string",
      "calls": 1,
      "errors": 1,
      "totalDurationMs": 1,
      "p95DurationMs": 1,
      "totalCpuMs": 1,
      "positiveHeapDeltaBytes": 1,
      "positiveRssDeltaBytes": 1,
      "surfaces": [
        {
          "surface": "api",
          "calls": 1,
          "errors": 1,
          "totalDurationMs": 1,
          "p95DurationMs": 1,
          "totalCpuMs": 1,
          "positiveHeapDeltaBytes": 1,
          "positiveRssDeltaBytes": 1
        }
      ],
      "topOperations": [
        {
          "moduleId": "string",
          "surface": "api",
          "operation": "string",
          "resourceId": null,
          "calls": 1,
          "errors": 1,
          "totalDurationMs": 1,
          "maxDurationMs": 1,
          "p95DurationMs": 1,
          "totalCpuUserMs": 1,
          "totalCpuSystemMs": 1,
          "maxCpuMs": 1,
          "totalHeapDeltaBytes": 1,
          "positiveHeapDeltaBytes": 1,
          "maxHeapDeltaBytes": 1,
          "totalRssDeltaBytes": 1,
          "positiveRssDeltaBytes": 1,
          "maxRssDeltaBytes": 1,
          "firstSeenAt": "string",
          "lastSeenAt": "string"
        }
      ],
      "candidateReasons": [
        "string"
      ]
    }
  ],
  "buckets": [
    {
      "bucketStart": "string",
      "bucketEnd": "string",
      "bucketIntervalMs": 1,
      "stage": "startup",
      "partial": true,
      "totals": {
        "modules": 1,
        "calls": 1,
        "errors": 1,
        "totalDurationMs": 1,
        "totalCpuMs": 1,
        "positiveHeapDeltaBytes": 1,
        "positiveRssDeltaBytes": 1
      },
      "modules": [
        {
          "moduleId": "string",
          "calls": 1,
          "errors": 1,
          "totalDurationMs": 1,
          "p95DurationMs": 1,
          "totalCpuMs": 1,
          "positiveHeapDeltaBytes": 1,
          "positiveRssDeltaBytes": 1,
          "surfaces": [
            {
              "surface": "api",
              "calls": 1,
              "errors": 1,
              "totalDurationMs": 1,
              "p95DurationMs": 1,
              "totalCpuMs": 1,
              "positiveHeapDeltaBytes": 1,
              "positiveRssDeltaBytes": 1
            }
          ],
          "topOperations": [
            {
              "moduleId": "string",
              "surface": "api",
              "operation": "string",
              "resourceId": null,
              "calls": 1,
              "errors": 1,
              "totalDurationMs": 1,
              "maxDurationMs": 1,
              "p95DurationMs": 1,
              "totalCpuUserMs": 1,
              "totalCpuSystemMs": 1,
              "maxCpuMs": 1,
              "totalHeapDeltaBytes": 1,
              "positiveHeapDeltaBytes": 1,
              "maxHeapDeltaBytes": 1,
              "totalRssDeltaBytes": 1,
              "positiveRssDeltaBytes": 1,
              "maxRssDeltaBytes": 1,
              "firstSeenAt": "string",
              "lastSeenAt": "string"
            }
          ],
          "candidateReasons": [
            "string"
          ]
        }
      ]
    }
  ]
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/configs/module-telemetry" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/configs/system-status`

Get system health status

Returns comprehensive system health information including environment details, version, resource usage, and service connectivity status.

**Tags:** Configs

**Requires authentication.**

### Responses

**200** – System status snapshot

Content-Type: `application/json`

```json
{
  "generatedAt": "string",
  "runtimeMode": "development",
  "categories": [
    {
      "key": "profiling",
      "labelKey": "string",
      "descriptionKey": null,
      "items": [
        {
          "key": "string",
          "category": "profiling",
          "kind": "boolean",
          "labelKey": "string",
          "descriptionKey": "string",
          "docUrl": null,
          "defaultValue": null,
          "state": "enabled",
          "value": null,
          "normalizedValue": null
        }
      ]
    }
  ]
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to load system status

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/configs/system-status" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/configs/system-status`

Clear system cache

Purges the entire cache for the current tenant. Useful for troubleshooting or forcing fresh data loading.

**Tags:** Configs

**Requires authentication.**

### Responses

**200** – Cache cleared successfully

Content-Type: `application/json`

```json
{
  "cleared": true
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to purge cache

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**503** – Cache service unavailable

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/configs/system-status" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/configs/upgrade-actions`

List pending upgrade actions

Returns a list of pending upgrade actions for the current version. These are one-time setup tasks that need to be executed after upgrading to a new version. Requires organization and tenant context.

**Tags:** Configs

**Requires authentication.**

### Responses

**200** – List of pending upgrade actions

Content-Type: `application/json`

```json
{
  "version": "string",
  "actions": [
    {
      "id": "string",
      "version": "string",
      "message": "string",
      "ctaLabel": "string",
      "successMessage": "string",
      "loadingLabel": "string"
    }
  ]
}
```

**400** – Missing organization or tenant context

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to load upgrade actions

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/configs/upgrade-actions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/configs/upgrade-actions`

Execute upgrade action

Executes a specific upgrade action by ID. Typically used for one-time setup tasks like seeding example data after version upgrade. Returns execution status and localized success message.

**Tags:** Configs

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "actionId": "string"
}
```

### Responses

**200** – Upgrade action executed successfully

Content-Type: `application/json`

```json
{
  "status": "string",
  "message": "string",
  "version": "string"
}
```

**400** – Invalid request body or missing context

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Upgrade actions are disabled

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to execute upgrade action

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/configs/upgrade-actions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"actionId\": \"string\"
}"
```

## GET `/coworker-tools`

Compatible Closare coworker tool catalog

**Tags:** Cowork tools

**Requires authentication.**

### Responses

**200** – Legacy tools envelope

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/coworker-tools" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/coworker-tools`

Compatible Closare approval policy update

**Tags:** Cowork tools

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "slug": "string",
  "toolName": "string",
  "requiresApproval": true
}
```

### Responses

**200** – Policy saved

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/coworker-tools" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"slug\": \"string\",
  \"toolName\": \"string\",
  \"requiresApproval\": true
}"
```

## POST `/coworker/llm/openai/v1/chat/completions`

Signed sandbox callback

Requires X-Coworker-Token bound to a current active plain-chat execution. Browser credentials are not accepted.

**Tags:** Closare Cowork Runtime

### Responses

**200** – Model stream when available

Content-Type: `application/json`

**204** – Telemetry disabled

**403** – Invalid or stale signed execution

Content-Type: `application/json`

**503** – Adapter unavailable

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/coworker/llm/openai/v1/chat/completions" \
  -H "Accept: application/json"
```

## POST `/coworker/mcp/{slug}`

Signed sandbox callback

Requires X-Coworker-Token bound to a current active plain-chat execution. Browser credentials are not accepted.

**Tags:** Closare Cowork Runtime

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| slug | path | any | Required |

### Responses

**200** – Model stream when available

Content-Type: `application/json`

**204** – Telemetry disabled

**403** – Invalid or stale signed execution

Content-Type: `application/json`

**503** – Adapter unavailable

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/coworker/mcp/:slug" \
  -H "Accept: application/json"
```

## POST `/coworker/otel/{path}`

Signed sandbox callback

Requires X-Coworker-Token bound to a current active plain-chat execution. Browser credentials are not accepted.

**Tags:** Closare Cowork Runtime

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| path | path | any | Required |

### Responses

**200** – Model stream when available

Content-Type: `application/json`

**204** – Telemetry disabled

**403** – Invalid or stale signed execution

Content-Type: `application/json`

**503** – Adapter unavailable

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/coworker/otel/:path" \
  -H "Accept: application/json"
```

## POST `/coworker/sdk/{coworkerId}/call`

Execute or request approval for an execution-bound integration tool

Requires X-Coworker-Sdk-Capability bound to the active execution and sandbox lease. Shared sandbox HMAC and browser credentials are not accepted.

**Tags:** Closare Cowork Runtime

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| coworkerId | path | any | Required |

### Responses

**200** – Tool result envelope or persisted approval handoff with endsTurn

Content-Type: `application/json`

**400** – Invalid tool request

Content-Type: `application/json`

**403** – Invalid or stale capability or forbidden tool

Content-Type: `application/json`

**409** – Integration revision conflict

Content-Type: `application/json`

**413** – Request exceeds 64 KiB or inline result exceeds 256 KiB

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/coworker/sdk/:coworkerId/call" \
  -H "Accept: application/json"
```

## DELETE `/currencies/currencies`

Delete currency

Deletes a currency by id.

**Tags:** Currencies

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Currency deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/currencies/currencies" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/currencies/currencies`

List currencies

Returns a paginated collection of currencies scoped to the authenticated organization.

**Tags:** Currencies

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | query | any | Optional |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| isBase | query | any | Optional |
| isActive | query | any | Optional |
| code | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated currencies

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "code": "string",
      "name": "string",
      "symbol": null,
      "decimalPlaces": 1,
      "thousandsSeparator": null,
      "decimalSeparator": null,
      "isBase": true,
      "isActive": true,
      "createdAt": null,
      "updatedAt": null,
      "organizationId": "string",
      "tenantId": "string"
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/currencies/currencies?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/currencies/currencies`

Create currency

Creates a new currency.

**Tags:** Currencies

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "string",
  "tenantId": "string",
  "code": "string",
  "name": "string",
  "symbol": null,
  "thousandsSeparator": null,
  "decimalSeparator": null
}
```

### Responses

**201** – Currency created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/currencies/currencies" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"string\",
  \"tenantId\": \"string\",
  \"code\": \"string\",
  \"name\": \"string\",
  \"symbol\": null,
  \"thousandsSeparator\": null,
  \"decimalSeparator\": null
}"
```

## PUT `/currencies/currencies`

Update currency

Updates an existing currency by id.

**Tags:** Currencies

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "string",
  "symbol": null,
  "thousandsSeparator": null,
  "decimalSeparator": null
}
```

### Responses

**200** – Currency updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/currencies/currencies" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"string\",
  \"symbol\": null,
  \"thousandsSeparator\": null,
  \"decimalSeparator\": null
}"
```

## GET `/currencies/currencies/options`

List currency options

Returns currencies formatted for select inputs.

**Tags:** Currencies

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| q | query | any | Optional |
| query | query | any | Optional |
| search | query | any | Optional |
| includeInactive | query | any | Optional |
| limit | query | any | Optional |

### Responses

**200** – Option list

Content-Type: `application/json`

```json
{
  "items": [
    {
      "value": "string",
      "label": "string"
    }
  ]
}
```

**400** – Invalid query

Content-Type: `application/json`

```json
{
  "items": []
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "items": []
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/currencies/currencies/options?limit=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/currencies/exchange-rates`

Delete exchangerate

Deletes an exchange rate by id.

**Tags:** Currencies

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – ExchangeRate deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/currencies/exchange-rates" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/currencies/exchange-rates`

List exchangerates

Returns a paginated collection of exchangerates scoped to the authenticated organization.

**Tags:** Currencies

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | query | any | Optional |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| fromCurrencyCode | query | any | Optional |
| toCurrencyCode | query | any | Optional |
| isActive | query | any | Optional |
| source | query | any | Optional |
| type | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated exchangerates

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "fromCurrencyCode": "string",
      "toCurrencyCode": "string",
      "rate": "string",
      "date": "string",
      "source": "string",
      "type": null,
      "isActive": true,
      "createdAt": null,
      "updatedAt": null,
      "organizationId": "00000000-0000-4000-8000-000000000000",
      "tenantId": "00000000-0000-4000-8000-000000000000"
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/currencies/exchange-rates?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/currencies/exchange-rates`

Create exchangerate

Creates a new exchange rate.

**Tags:** Currencies

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "string",
  "tenantId": "string",
  "fromCurrencyCode": "string",
  "toCurrencyCode": "string",
  "rate": "string",
  "type": null
}
```

### Responses

**201** – ExchangeRate created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/currencies/exchange-rates" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"string\",
  \"tenantId\": \"string\",
  \"fromCurrencyCode\": \"string\",
  \"toCurrencyCode\": \"string\",
  \"rate\": \"string\",
  \"type\": null
}"
```

## PUT `/currencies/exchange-rates`

Update exchangerate

Updates an existing exchange rate by id.

**Tags:** Currencies

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "string",
  "type": null
}
```

### Responses

**200** – ExchangeRate updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/currencies/exchange-rates" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"string\",
  \"type\": null
}"
```

## DELETE `/currencies/fetch-configs`

Delete currency fetch configuration

Deletes a currency fetch configuration by id.

**Tags:** Currencies

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | query | any | Required. Currency fetch configuration identifier to delete |

### Responses

**200** – Currency fetch configuration deleted successfully

Content-Type: `application/json`

```json
{
  "success": true
}
```

**400** – Bad request

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/currencies/fetch-configs?id=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/currencies/fetch-configs`

List currency fetch configurations

Returns all currency fetch configurations scoped to the authenticated organization.

**Tags:** Currencies

**Requires authentication.**

### Responses

**200** – A list of currency fetch configurations

Content-Type: `application/json`

```json
{
  "configs": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "organizationId": "00000000-0000-4000-8000-000000000000",
      "tenantId": "00000000-0000-4000-8000-000000000000",
      "provider": "string",
      "isEnabled": true,
      "syncTime": null,
      "lastSyncAt": null,
      "lastSyncStatus": null,
      "lastSyncMessage": null,
      "lastSyncCount": null,
      "config": null,
      "createdAt": "string",
      "updatedAt": "string"
    }
  ]
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/currencies/fetch-configs" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/currencies/fetch-configs`

Create currency fetch configuration

Creates a new currency fetch configuration.

**Tags:** Currencies

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "provider": "NBP",
  "isEnabled": false,
  "syncTime": null,
  "config": null
}
```

### Responses

**201** – Currency fetch configuration created successfully

Content-Type: `application/json`

```json
{
  "config": {
    "id": "00000000-0000-4000-8000-000000000000",
    "organizationId": "00000000-0000-4000-8000-000000000000",
    "tenantId": "00000000-0000-4000-8000-000000000000",
    "provider": "string",
    "isEnabled": true,
    "syncTime": null,
    "lastSyncAt": null,
    "lastSyncStatus": null,
    "lastSyncMessage": null,
    "lastSyncCount": null,
    "config": null,
    "createdAt": "string",
    "updatedAt": "string"
  }
}
```

**400** – Bad request

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/currencies/fetch-configs" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"provider\": \"NBP\",
  \"isEnabled\": false,
  \"syncTime\": null,
  \"config\": null
}"
```

## PUT `/currencies/fetch-configs`

Update currency fetch configuration

Updates an existing currency fetch configuration by id.

**Tags:** Currencies

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "syncTime": null,
  "config": null,
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Currency fetch configuration updated successfully

Content-Type: `application/json`

```json
{
  "config": {
    "id": "00000000-0000-4000-8000-000000000000",
    "organizationId": "00000000-0000-4000-8000-000000000000",
    "tenantId": "00000000-0000-4000-8000-000000000000",
    "provider": "string",
    "isEnabled": true,
    "syncTime": null,
    "lastSyncAt": null,
    "lastSyncStatus": null,
    "lastSyncMessage": null,
    "lastSyncCount": null,
    "config": null,
    "createdAt": "string",
    "updatedAt": "string"
  }
}
```

**400** – Bad request

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/currencies/fetch-configs" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"syncTime\": null,
  \"config\": null,
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## POST `/currencies/fetch-rates`

Fetch currency rates

Fetches currency exchange rates from configured providers for a specific date.

**Tags:** Currencies

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Currency rates fetched successfully

Content-Type: `application/json`

```json
{
  "totalFetched": 1,
  "byProvider": {
    "key": {
      "count": 1
    }
  },
  "errors": [
    "string"
  ]
}
```

**400** – Bad request

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Internal server error

Content-Type: `application/json`

```json
{
  "totalFetched": 1,
  "byProvider": {
    "key": {
      "count": 1
    }
  },
  "errors": [
    "string"
  ]
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/currencies/fetch-rates" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## DELETE `/customers/activities`

Delete activity

DEPRECATED (sunset 2026-06-30): Deletes an activity. Use DELETE /api/customers/interactions instead.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Activity deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/customers/activities" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/customers/activities`

List activitys

Returns a paginated collection of activitys scoped to the authenticated organization.

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| entityId | query | any | Optional |
| dealId | query | any | Optional |
| activityType | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated activitys

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "activityType": "string",
      "subject": null,
      "body": null,
      "occurredAt": null,
      "createdAt": "string",
      "appearanceIcon": null,
      "appearanceColor": null,
      "entityId": null,
      "authorUserId": null,
      "authorName": null,
      "authorEmail": null,
      "dealId": null,
      "dealTitle": null,
      "customValues": null,
      "activityTypeLabel": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/activities?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/activities`

Create activity

DEPRECATED (sunset 2026-06-30): Creates a timeline activity. Use POST /api/customers/interactions instead.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "entityId": "00000000-0000-4000-8000-000000000000",
  "activityType": "string",
  "phoneNumber": null,
  "appearanceIcon": null,
  "appearanceColor": null
}
```

### Responses

**201** – Activity created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/customers/activities" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityId\": \"00000000-0000-4000-8000-000000000000\",
  \"activityType\": \"string\",
  \"phoneNumber\": null,
  \"appearanceIcon\": null,
  \"appearanceColor\": null
}"
```

## PUT `/customers/activities`

Update activity

DEPRECATED (sunset 2026-06-30): Updates an activity. Use PUT /api/customers/interactions instead.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "phoneNumber": null,
  "appearanceIcon": null,
  "appearanceColor": null
}
```

### Responses

**200** – Activity updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/customers/activities" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"phoneNumber\": null,
  \"appearanceIcon\": null,
  \"appearanceColor\": null
}"
```

## DELETE `/customers/addresses`

Delete address

Deletes an address by id. The identifier may be included in the body or query.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Address deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/customers/addresses" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/customers/addresses`

List addresss

Returns a paginated collection of addresss scoped to the authenticated organization.

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| entityId | query | any | Optional |
| id | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated addresss

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "entity_id": "00000000-0000-4000-8000-000000000000",
      "name": null,
      "purpose": null,
      "company_name": null,
      "address_line1": null,
      "address_line2": null,
      "building_number": null,
      "flat_number": null,
      "city": null,
      "region": null,
      "postal_code": null,
      "country": null,
      "latitude": null,
      "longitude": null,
      "is_primary": null,
      "organization_id": null,
      "tenant_id": null,
      "updated_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/addresses?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/addresses`

Create address

Creates a customer address record and associates it with the referenced entity.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "entityId": "00000000-0000-4000-8000-000000000000",
  "addressLine1": "string",
  "latitude": null,
  "longitude": null
}
```

### Responses

**201** – Address created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/customers/addresses" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"entityId\": \"00000000-0000-4000-8000-000000000000\",
  \"addressLine1\": \"string\",
  \"latitude\": null,
  \"longitude\": null
}"
```

## PUT `/customers/addresses`

Update address

Updates fields on an existing customer address.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "latitude": null,
  "longitude": null
}
```

### Responses

**200** – Address updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/customers/addresses" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"latitude\": null,
  \"longitude\": null
}"
```

## GET `/customers/assignable-staff`

DEPRECATED: use GET /api/staff/team-members/assignable instead.

Deprecated. Returns 308 Permanent Redirect to /api/staff/team-members/assignable preserving the query string. Will be removed no earlier than the next major release.

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |

### Responses

**200** – Assignable staff members (only reachable by following the redirect).

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "teamMemberId": "00000000-0000-4000-8000-000000000000",
      "userId": "00000000-0000-4000-8000-000000000000",
      "displayName": "string",
      "email": null,
      "teamName": null,
      "user": null,
      "team": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

**308** – Permanent redirect to /api/staff/team-members/assignable.

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**400** – Invalid request

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Forbidden

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/assignable-staff?page=1&pageSize=24" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/customers/comments`

Delete comment

Deletes a comment identified by `id` supplied via body or query string.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Comment deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/customers/comments" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/customers/comments`

List comments

Returns a paginated collection of comments scoped to the authenticated organization.

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| entityId | query | any | Optional |
| dealId | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated comments

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "entity_id": null,
      "deal_id": null,
      "body": null,
      "author_user_id": null,
      "appearance_icon": null,
      "appearance_color": null,
      "organization_id": null,
      "tenant_id": null,
      "created_at": null,
      "updated_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/comments?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/comments`

Create comment

Adds a comment to a customer timeline.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "entityId": "00000000-0000-4000-8000-000000000000",
  "body": "string",
  "appearanceIcon": null,
  "appearanceColor": null
}
```

### Responses

**201** – Comment created

Content-Type: `application/json`

```json
{
  "id": null,
  "authorUserId": null
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/customers/comments" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"entityId\": \"00000000-0000-4000-8000-000000000000\",
  \"body\": \"string\",
  \"appearanceIcon\": null,
  \"appearanceColor\": null
}"
```

## PUT `/customers/comments`

Update comment

Updates an existing timeline comment.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "appearanceIcon": null,
  "appearanceColor": null
}
```

### Responses

**200** – Comment updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/customers/comments" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"appearanceIcon\": null,
  \"appearanceColor\": null
}"
```

## DELETE `/customers/companies`

Delete company

Deletes a company by id. The identifier can be provided via body or query.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Company deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**422** – Company has dependent records (people, deals, or direct staff); unlink or reassign before delete.

Content-Type: `application/json`

```json
{
  "error": "string",
  "code": "COMPANY_HAS_DEPENDENTS"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/customers/companies" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/customers/companies`

List companies

Returns a paginated collection of companies scoped to the authenticated organization.

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| email | query | any | Optional |
| emailStartsWith | query | any | Optional |
| emailContains | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| status | query | any | Optional |
| lifecycleStage | query | any | Optional |
| source | query | any | Optional |
| hasEmail | query | any | Optional |
| hasPhone | query | any | Optional |
| hasNextInteraction | query | any | Optional |
| createdFrom | query | any | Optional |
| createdTo | query | any | Optional |
| id | query | any | Optional |
| tagIds | query | any | Optional |
| tagIdsEmpty | query | any | Optional |
| excludeIds | query | any | Optional |
| excludeLinkedPersonId | query | any | Optional |
| excludeLinkedCompanyId | query | any | Optional |
| excludeLinkedDealId | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated companies

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "description": null,
      "owner_user_id": null,
      "primary_email": null,
      "primary_phone": null,
      "status": null,
      "lifecycle_stage": null,
      "source": null,
      "next_interaction_at": null,
      "next_interaction_name": null,
      "next_interaction_ref_id": null,
      "next_interaction_icon": null,
      "next_interaction_color": null,
      "organization_id": null,
      "tenant_id": null,
      "created_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/companies?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/companies`

Create company

Creates a company record and associated profile data.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "displayName": "string",
  "description": null,
  "primaryEmail": null,
  "primaryPhone": null,
  "nextInteraction": null,
  "legalName": null,
  "brandName": null,
  "domain": null,
  "websiteUrl": null,
  "sizeBucket": null,
  "annualRevenue": null
}
```

### Responses

**201** – Company created

Content-Type: `application/json`

```json
{
  "id": null,
  "companyId": null
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/customers/companies" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"displayName\": \"string\",
  \"description\": null,
  \"primaryEmail\": null,
  \"primaryPhone\": null,
  \"nextInteraction\": null,
  \"legalName\": null,
  \"brandName\": null,
  \"domain\": null,
  \"websiteUrl\": null,
  \"sizeBucket\": null,
  \"annualRevenue\": null
}"
```

## PUT `/customers/companies`

Update company

Updates company profile fields, tags, or custom attributes.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "description": null,
  "primaryEmail": null,
  "primaryPhone": null,
  "nextInteraction": null,
  "legalName": null,
  "brandName": null,
  "domain": null,
  "websiteUrl": null,
  "sizeBucket": null,
  "annualRevenue": null
}
```

### Responses

**200** – Company updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/customers/companies" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"description\": null,
  \"primaryEmail\": null,
  \"primaryPhone\": null,
  \"nextInteraction\": null,
  \"legalName\": null,
  \"brandName\": null,
  \"domain\": null,
  \"websiteUrl\": null,
  \"sizeBucket\": null,
  \"annualRevenue\": null
}"
```

## GET `/customers/companies/{id}`

Fetch company with related data

Returns a company customer record with optional related resources such as addresses, comments, activities, interactions, deals, todos, and linked people.

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| include | query | any | Optional. Comma-separated list of relations to include (addresses, comments, activities, interactions, deals, todos, people). |

### Responses

**200** – Company detail payload

Content-Type: `application/json`

```json
{
  "interactionMode": "canonical",
  "company": {
    "id": "00000000-0000-4000-8000-000000000000",
    "displayName": null,
    "description": null,
    "ownerUserId": null,
    "primaryEmail": null,
    "primaryPhone": null,
    "status": null,
    "lifecycleStage": null,
    "source": null,
    "nextInteractionAt": null,
    "nextInteractionName": null,
    "nextInteractionRefId": null,
    "nextInteractionIcon": null,
    "nextInteractionColor": null,
    "organizationId": null,
    "tenantId": null,
    "temperature": null,
    "renewalQuarter": null,
    "createdAt": "string",
    "updatedAt": "string"
  },
  "profile": null,
  "customFields": {},
  "tags": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "label": "string",
      "color": null
    }
  ],
  "addresses": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": null,
      "purpose": null,
      "addressLine1": null,
      "addressLine2": null,
      "buildingNumber": null,
      "flatNumber": null,
      "city": null,
      "region": null,
      "postalCode": null,
      "country": null,
      "latitude": null,
      "longitude": null,
      "isPrimary": null,
      "createdAt": "string"
    }
  ],
  "comments": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "body": null,
      "authorUserId": null,
      "authorName": null,
      "authorEmail": null,
      "dealId": null,
      "createdAt": "string",
      "appearanceIcon": null,
      "appearanceColor": null
    }
  ],
  "activities": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "activityType": "string",
      "subject": null,
      "body": null,
      "occurredAt": null,
      "dealId": null,
      "authorUserId": null,
      "authorName": null,
      "authorEmail": null,
      "createdAt": "string",
      "appearanceIcon": null,
      "appearanceColor": null
    }
  ],
  "interactions": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "entityId": null,
      "interactionType": "string",
      "title": null,
      "body": null,
      "status": "string",
      "scheduledAt": null,
      "occurredAt": null,
      "priority": null,
      "authorUserId": null,
      "ownerUserId": null,
      "dealId": null,
      "organizationId": null,
      "tenantId": null,
      "authorName": null,
      "authorEmail": null,
      "dealTitle": null,
      "customValues": null,
      "appearanceIcon": null,
      "appearanceColor": null,
      "source": null,
      "createdAt": "string",
      "updatedAt": "string"
    }
  ],
  "deals": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "title": null,
      "status": null,
      "pipelineStage": null,
      "valueAmount": null,
      "valueCurrency": null,
      "probability": null,
      "expectedCloseAt": null,
      "ownerUserId": null,
      "source": null,
      "createdAt": "string",
      "updatedAt": "string"
    }
  ],
  "todos": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "todoId": "00000000-0000-4000-8000-000000000000",
      "todoSource": "string",
      "createdAt": "string",
      "createdByUserId": null,
      "title": null,
      "isDone": null,
      "priority": null,
      "severity": null,
      "description": null,
      "dueAt": null,
      "todoOrganizationId": null,
      "customValues": null
    }
  ],
  "people": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "displayName": null,
      "primaryEmail": null,
      "primaryPhone": null,
      "status": null,
      "lifecycleStage": null,
      "jobTitle": null,
      "department": null,
      "createdAt": "string",
      "organizationId": null,
      "source": null,
      "temperature": null,
      "linkedAt": null
    }
  ],
  "viewer": {
    "userId": null,
    "name": null,
    "email": null
  }
}
```

**400** – Invalid identifier

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Forbidden for tenant/organization scope

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Company not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/companies/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/companies/{id}/people`

List linked people for a company

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| sort | query | any | Optional |

### Responses

**200** – Paginated linked people

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "displayName": "string",
      "primaryEmail": null,
      "primaryPhone": null,
      "status": null,
      "lifecycleStage": null,
      "jobTitle": null,
      "department": null,
      "createdAt": "string",
      "organizationId": null,
      "temperature": null,
      "source": null,
      "linkedAt": null
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/companies/:id/people?page=1&pageSize=20&sort=name-asc" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/customers/companies/{id}/roles`

Remove a company role assignment

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| roleId | query | any | Required |

### Responses

**200** – Role deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Invalid request

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Role not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/customers/companies/00000000-0000-4000-8000-000000000000/roles?roleId=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/companies/{id}/roles`

List roles for a company

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Role assignments

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "entityType": "company",
      "entityId": "00000000-0000-4000-8000-000000000000",
      "userId": "00000000-0000-4000-8000-000000000000",
      "userName": null,
      "userEmail": null,
      "userPhone": null,
      "roleType": "string",
      "createdAt": "string",
      "updatedAt": "string"
    }
  ]
}
```

**400** – Invalid request

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/companies/00000000-0000-4000-8000-000000000000/roles" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/companies/{id}/roles`

Assign a role to a company

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "roleType": "string",
  "userId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**201** – Role created

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

**400** – Invalid request

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**409** – Role already assigned

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/customers/companies/00000000-0000-4000-8000-000000000000/roles" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"roleType\": \"string\",
  \"userId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## PUT `/customers/companies/{id}/roles`

Update a company role assignment

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| roleId | query | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "userId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Role updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Invalid request

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Role not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/customers/companies/00000000-0000-4000-8000-000000000000/roles?roleId=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"userId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/customers/dashboard/widgets/customer-todos`

Fetch recent customer tasks

Returns the most recent customer tasks for display on dashboards, including legacy compatibility rows when needed.

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| limit | query | any | Optional |
| tenantId | query | any | Optional |
| organizationId | query | any | Optional |

### Responses

**200** – Widget payload

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "todoId": "00000000-0000-4000-8000-000000000000",
      "todoSource": "string",
      "todoTitle": null,
      "createdAt": "string",
      "organizationId": null,
      "entity": {
        "id": null,
        "displayName": null,
        "kind": null,
        "ownerUserId": null
      }
    }
  ]
}
```

**400** – Invalid query parameters

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Requested scope is not accessible

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Widget failed to load

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/dashboard/widgets/customer-todos?limit=5" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/dashboard/widgets/new-customers`

Fetch recently created customers

Returns the latest customers created within the scoped tenant/organization for dashboard display.

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| limit | query | any | Optional |
| tenantId | query | any | Optional |
| organizationId | query | any | Optional |
| kind | query | any | Optional |

### Responses

**200** – Widget payload

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "displayName": null,
      "kind": null,
      "organizationId": null,
      "createdAt": "string",
      "ownerUserId": null
    }
  ]
}
```

**400** – Invalid query parameters

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Requested scope is not accessible

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Widget failed to load

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/dashboard/widgets/new-customers?limit=5" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/dashboard/widgets/new-deals`

Fetch recently created deals

Returns the latest deals created within the scoped tenant/organization for dashboard display.

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| limit | query | any | Optional |
| tenantId | query | any | Optional |
| organizationId | query | any | Optional |

### Responses

**200** – Widget payload

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "title": null,
      "status": null,
      "organizationId": null,
      "createdAt": "string",
      "ownerUserId": null,
      "valueAmount": null,
      "valueCurrency": null
    }
  ]
}
```

**400** – Invalid query parameters

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Requested scope is not accessible

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Widget failed to load

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/dashboard/widgets/new-deals?limit=5" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/dashboard/widgets/next-interactions`

Fetch upcoming customer interactions

Lists upcoming (or optionally past) customer interaction reminders ordered by interaction date.

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| limit | query | any | Optional |
| tenantId | query | any | Optional |
| organizationId | query | any | Optional |
| includePast | query | any | Optional |

### Responses

**200** – Widget payload

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "displayName": null,
      "kind": null,
      "organizationId": null,
      "nextInteractionAt": null,
      "nextInteractionName": null,
      "nextInteractionIcon": null,
      "nextInteractionColor": null,
      "ownerUserId": null
    }
  ],
  "now": "string"
}
```

**400** – Invalid query parameters

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Requested scope is not accessible

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Widget failed to load

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/dashboard/widgets/next-interactions?limit=5" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/customers/deals`

Delete deal

Deletes a deal by `id`. The identifier may be provided in the body or query parameters.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Deal deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/customers/deals" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/customers/deals`

List deals

Returns a paginated collection of deals scoped to the authenticated organization.

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| id | query | any | Optional |
| search | query | any | Optional |
| status | query | any | Optional |
| pipelineStage | query | any | Optional |
| pipelineId | query | any | Optional |
| pipelineStageId | query | any | Optional |
| ownerUserId | query | any | Optional |
| expectedCloseAtFrom | query | any | Optional |
| expectedCloseAtTo | query | any | Optional |
| isStuck | query | any | Optional |
| isOverdue | query | any | Optional |
| needsAttention | query | any | Optional |
| valueCurrency | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| personEntityId | query | any | Optional. Deprecated; use personId |
| companyEntityId | query | any | Optional. Deprecated; use companyId |
| personId | query | any | Optional |
| companyId | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated deals

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "title": null,
      "description": null,
      "status": null,
      "pipeline_stage": null,
      "pipeline_id": null,
      "pipeline_stage_id": null,
      "value_amount": null,
      "value_currency": null,
      "probability": null,
      "expected_close_at": null,
      "owner_user_id": null,
      "source": null,
      "organization_id": null,
      "tenant_id": null,
      "created_at": null,
      "updated_at": null,
      "organizationId": null,
      "tenantId": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/deals?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/deals`

Create deal

Creates a sales deal, optionally associating people and companies.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "title": "string",
  "ownerUserId": null,
  "primaryPersonEntityId": null
}
```

### Responses

**201** – Deal created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/customers/deals" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"title\": \"string\",
  \"ownerUserId\": null,
  \"primaryPersonEntityId\": null
}"
```

## PUT `/customers/deals`

Update deal

Updates pipeline position, metadata, or associations for an existing deal.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "ownerUserId": null,
  "primaryPersonEntityId": null
}
```

### Responses

**200** – Deal updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/customers/deals" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"ownerUserId\": null,
  \"primaryPersonEntityId\": null
}"
```

## GET `/customers/deals/{id}`

Fetch deal with associations and pipeline context

Returns a deal with linked people, companies, closure fields, optional pipeline history, custom fields, and viewer context.

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| include | query | any | Optional |

### Responses

**200** – Deal detail payload

Content-Type: `application/json`

```json
{
  "deal": {
    "id": "00000000-0000-4000-8000-000000000000",
    "title": null,
    "description": null,
    "status": null,
    "pipelineStage": null,
    "pipelineId": null,
    "pipelineStageId": null,
    "valueAmount": null,
    "valueCurrency": null,
    "probability": null,
    "expectedCloseAt": null,
    "ownerUserId": null,
    "source": null,
    "closureOutcome": null,
    "lossReasonId": null,
    "lossNotes": null,
    "organizationId": null,
    "tenantId": null,
    "createdAt": "string",
    "updatedAt": "string"
  },
  "people": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "label": "string",
      "subtitle": null,
      "kind": "person"
    }
  ],
  "companies": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "label": "string",
      "subtitle": null,
      "kind": "company"
    }
  ],
  "customFields": {},
  "viewer": {
    "userId": null,
    "name": null,
    "email": null
  },
  "pipelineStages": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "label": "string",
      "order": 1,
      "color": null,
      "icon": null
    }
  ],
  "stageTransitions": [
    {
      "stageId": "00000000-0000-4000-8000-000000000000",
      "stageLabel": "string",
      "stageOrder": 1,
      "transitionedAt": "string"
    }
  ],
  "owner": null
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Forbidden for tenant/organization scope

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Deal not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/deals/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/deals/{id}/companies`

List linked companies for a deal

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| sort | query | any | Optional |

### Responses

**200** – Paginated linked companies

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "label": "string",
      "subtitle": null,
      "kind": "company",
      "linkedAt": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/deals/:id/companies?page=1&pageSize=20&sort=label-asc" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/deals/{id}/people`

List linked people for a deal

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| sort | query | any | Optional |

### Responses

**200** – Paginated linked people

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "label": "string",
      "subtitle": null,
      "kind": "person",
      "linkedAt": "string",
      "isPrimary": true
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/deals/:id/people?page=1&pageSize=20&sort=label-asc" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/deals/{id}/stats`

Fetch analytics for a closed deal

Returns week-to-date closure counts, sales cycle length, quarter ranking, and loss reason context for a closed deal.

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Deal closure stats payload

Content-Type: `application/json`

```json
{
  "dealValue": null,
  "dealCurrency": null,
  "closureOutcome": "won",
  "closedAt": "string",
  "pipelineName": null,
  "dealsClosedThisPeriod": 1,
  "salesCycleDays": null,
  "dealRankInQuarter": null,
  "lossReason": null
}
```

**400** – Deal is not closed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Forbidden for tenant/organization scope

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Deal not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/deals/:id/stats" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/deals/aggregate`

Per-stage counts and currency totals for kanban lane headers

Returns per-stage counts and totals for deals, with values converted to the tenant base currency where rates are available. Used to power kanban lane headers without loading every deal.

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| pipelineId | query | any | Optional |
| search | query | any | Optional |
| status | query | any | Optional |
| ownerUserId | query | any | Optional |
| personId | query | any | Optional |
| companyId | query | any | Optional |
| isStuck | query | any | Optional |
| isOverdue | query | any | Optional |
| expectedCloseAtFrom | query | any | Optional |
| expectedCloseAtTo | query | any | Optional |

### Responses

**200** – Per-stage aggregate payload

Content-Type: `application/json`

```json
{
  "baseCurrencyCode": null,
  "perStage": [
    {
      "stageId": "string",
      "count": 1,
      "openCount": 1,
      "totalInBaseCurrency": 1,
      "byCurrency": [
        {
          "currency": "string",
          "total": 1,
          "count": 1
        }
      ],
      "convertedAll": true,
      "missingRateCurrencies": [
        "string"
      ]
    }
  ]
}
```

**400** – Invalid query parameters

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/deals/aggregate" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/deals/bulk-update-owner`

Bulk reassign deal owner

Queues a background job that reassigns the listed deals to a new owner (or clears the owner when null).

**Tags:** Customer Relationship Management

**Requires authentication.**

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/customers/deals/bulk-update-owner" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/deals/bulk-update-stage`

Bulk update deal pipeline stage

Queues a background job that moves the listed deals to the same pipeline stage. Returns a progress job id to poll for completion.

**Tags:** Customer Relationship Management

**Requires authentication.**

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/customers/deals/bulk-update-stage" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/deals/map`

Paginated deals that have a resolvable map location

Returns a page of deals that have a coordinate-bearing linked company/person address, each enriched with one resolved location (company primary first, then earliest created; person addresses as fallback). Deals with no coordinate-bearing address are excluded entirely, so every item carries a non-null location in normal operation; the schema keeps location nullable only for the rare case where the address is deleted between the located-deal resolution and the page fetch.

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| id | query | any | Optional |
| search | query | any | Optional |
| status | query | any | Optional |
| pipelineStage | query | any | Optional |
| pipelineId | query | any | Optional |
| pipelineStageId | query | any | Optional |
| ownerUserId | query | any | Optional |
| expectedCloseAtFrom | query | any | Optional |
| expectedCloseAtTo | query | any | Optional |
| isStuck | query | any | Optional |
| isOverdue | query | any | Optional |
| needsAttention | query | any | Optional |
| valueCurrency | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| personEntityId | query | any | Optional. Deprecated; use personId |
| companyEntityId | query | any | Optional. Deprecated; use companyId |
| personId | query | any | Optional |
| companyId | query | any | Optional |

### Responses

**200** – Paged located deals

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "title": null,
      "status": null,
      "pipelineId": null,
      "pipelineStageId": null,
      "pipelineStage": null,
      "valueAmount": null,
      "valueCurrency": null,
      "probability": null,
      "expectedCloseAt": null,
      "ownerUserId": null,
      "updatedAt": null,
      "companies": [
        {
          "id": "00000000-0000-4000-8000-000000000000",
          "label": null
        }
      ],
      "people": [
        {
          "id": "00000000-0000-4000-8000-000000000000",
          "label": null
        }
      ],
      "location": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

**400** – Invalid query parameters

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Missing required features

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/deals/map?page=1&pageSize=100" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/deals/summary`

Pipeline KPI metrics with period-over-period deltas for the deals list

Returns the four list-level KPI cards (pipeline value, active deals, won this quarter, win rate) with quarter-over-quarter deltas, per-stage open-pipeline breakdown, top owners, and a 6-month win-rate series. Values are converted to the tenant base currency where rates are available; partial conversions are disclosed via convertedAll/missingRateCurrencies.

**Tags:** Customers

**Requires authentication.**

### Responses

**200** – Deals KPI summary payload

Content-Type: `application/json`

```json
{
  "baseCurrencyCode": null,
  "convertedAll": true,
  "missingRateCurrencies": [
    "string"
  ],
  "pipelineValue": {
    "value": 1,
    "delta": {
      "value": 1,
      "direction": "up"
    },
    "stages": [
      {
        "stage": null,
        "count": 1,
        "value": 1
      }
    ]
  },
  "activeDeals": {
    "value": 1,
    "delta": {
      "value": 1,
      "direction": "up"
    },
    "ownersCount": 1,
    "needAttention": 1,
    "owners": [
      {
        "id": "string",
        "count": 1
      }
    ],
    "ownersOverflow": 1
  },
  "wonThisQuarter": {
    "value": 1,
    "delta": {
      "value": 1,
      "direction": "up"
    },
    "dealsClosed": 1,
    "avgDeal": 1
  },
  "winRate": {
    "value": 1,
    "deltaPp": 1,
    "direction": "up",
    "previousValue": 1,
    "series": [
      {
        "period": "string",
        "rate": 1
      }
    ]
  }
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/deals/summary" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/dictionaries/{kind}`

List dictionary entries

Returns dictionary entries for the requested kind within the currently selected organization.

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| kind | path | any | Required |

### Responses

**200** – Dictionary entries

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "value": "string",
      "label": null,
      "color": null,
      "icon": null,
      "organizationId": null
    }
  ]
}
```

**400** – Failed to resolve dictionary context

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/dictionaries/:kind" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/dictionaries/{kind}`

Create or override dictionary entry

Creates a dictionary entry (or updates the existing entry for the same value) within the current organization scope.

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| kind | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "value": "string"
}
```

### Responses

**200** – Dictionary entry updated

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "value": "string",
  "label": null,
  "color": null,
  "icon": null,
  "organizationId": null
}
```

**201** – Dictionary entry created

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "value": "string",
  "label": null,
  "color": null,
  "icon": null,
  "organizationId": null
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**409** – Duplicate value conflict

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/customers/dictionaries/:kind" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"value\": \"string\"
}"
```

## DELETE `/customers/dictionaries/{kind}/{id}`

Delete dictionary entry

Removes a customer dictionary entry by identifier.

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| kind | path | any | Required |
| id | path | any | Required |

### Responses

**200** – Entry deleted

Content-Type: `application/json`

```json
{
  "success": true
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Entry not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**409** – Entry is in use and cannot be deleted

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/customers/dictionaries/:kind/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PATCH `/customers/dictionaries/{kind}/{id}`

Update dictionary entry

Updates value, label, color, or icon for an existing customer dictionary entry.

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| kind | path | any | Required |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Updated dictionary entry

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "value": "string",
  "label": null,
  "color": null,
  "icon": null,
  "organizationId": null
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Entry not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**409** – Duplicate value conflict

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PATCH "https://demo-carrier.closare.com/api/customers/dictionaries/:kind/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## GET `/customers/dictionaries/currency`

Resolve currency dictionary

Returns the active currency dictionary for the current organization scope, falling back to shared entries when required.

**Tags:** Customers

**Requires authentication.**

### Responses

**200** – Currency dictionary entries

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "entries": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "value": "string",
      "label": null
    }
  ]
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Currency dictionary missing

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Unexpected error

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/dictionaries/currency" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/dictionaries/kind-settings`

List kind settings

Returns selection mode and visibility settings for each dictionary kind.

**Tags:** Customers

**Requires authentication.**

### Responses

**200** – Kind settings

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "kind": "string",
      "selectionMode": "single",
      "visibleInTags": true,
      "sortOrder": 1
    }
  ]
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/dictionaries/kind-settings" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PATCH `/customers/dictionaries/kind-settings`

Update kind setting

Creates or updates settings for a specific dictionary kind.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "kind": "string"
}
```

### Responses

**200** – Setting updated

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "kind": "string",
  "selectionMode": "single",
  "visibleInTags": true,
  "sortOrder": 1
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PATCH "https://demo-carrier.closare.com/api/customers/dictionaries/kind-settings" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"kind\": \"string\"
}"
```

## DELETE `/customers/interactions`

Delete interaction

Soft-deletes an interaction identified by `id`. Accepts id via body or query string.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Interaction deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/customers/interactions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/customers/interactions`

List interactions

Returns a paginated collection of interactions scoped to the authenticated organization.

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| limit | query | any | Optional |
| cursor | query | any | Optional |
| entityId | query | any | Optional |
| dealId | query | any | Optional |
| status | query | any | Optional |
| interactionType | query | any | Optional |
| type | query | any | Optional |
| excludeInteractionType | query | any | Optional |
| search | query | any | Optional |
| from | query | any | Optional |
| to | query | any | Optional |
| recurrenceMasters | query | any | Optional |
| pinned | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated interactions

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "entityId": null,
      "dealId": null,
      "interactionType": "string",
      "title": null,
      "body": null,
      "status": "string",
      "scheduledAt": null,
      "occurredAt": null,
      "priority": null,
      "authorUserId": null,
      "ownerUserId": null,
      "appearanceIcon": null,
      "appearanceColor": null,
      "source": null,
      "duration": null,
      "durationMinutes": null,
      "location": null,
      "allDay": null,
      "recurrenceRule": null,
      "recurrenceEnd": null,
      "participants": null,
      "reminderMinutes": null,
      "visibility": null,
      "linkedEntities": null,
      "guestPermissions": null,
      "organizationId": null,
      "tenantId": null,
      "createdAt": null,
      "updatedAt": null,
      "authorName": null,
      "authorEmail": null,
      "dealTitle": null,
      "customValues": null
    }
  ]
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/interactions?limit=25" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/interactions`

Create interaction

Creates a new interaction linked to a customer entity or deal.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

No example available for this content type.

### Responses

**201** – Interaction created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/customers/interactions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/customers/interactions`

Update interaction

Updates fields for an existing interaction.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

No example available for this content type.

### Responses

**200** – Interaction updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/customers/interactions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PATCH `/customers/interactions/{id}/visibility`

Flip an email interaction visibility (private ↔ shared)

**Tags:** Customers, Email

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Updated

Content-Type: `application/json`

**400** – Invalid id

Content-Type: `application/json`

**401** – Unauthorized

Content-Type: `application/json`

**404** – Email not found or not visible to caller

Content-Type: `application/json`

**422** – Invalid body

Content-Type: `application/json`

### Example

```bash
curl -X PATCH "https://demo-carrier.closare.com/api/customers/interactions/:id/visibility" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/interactions/cancel`

Cancel an interaction

Marks an interaction as canceled.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Interaction canceled

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Interaction not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/customers/interactions/cancel" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## POST `/customers/interactions/complete`

Complete an interaction

Marks an interaction as done and sets occurredAt to current time (or a provided timestamp).

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Interaction completed

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Interaction not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/customers/interactions/complete" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/customers/interactions/conflicts`

Detect scheduling conflicts

Checks for overlapping planned interactions within the requested time window.

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| date | query | any | Required |
| startTime | query | any | Required |
| duration | query | any | Required |
| excludeId | query | any | Optional |
| userId | query | any | Optional |
| timezoneOffsetMinutes | query | any | Optional |

### Responses

**200** – Conflict detection result

Content-Type: `application/json`

```json
{
  "ok": true,
  "result": {
    "hasConflicts": true,
    "conflicts": [
      {
        "id": "string",
        "title": null,
        "startTime": "string",
        "endTime": "string",
        "type": "string"
      }
    ]
  }
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/interactions/conflicts?date=string&startTime=string&duration=1" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/interactions/counts`

Get interaction counts by type

Returns per-type interaction counts scoped to an entity.

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| entityId | query | any | Required |
| status | query | any | Optional |

### Responses

**200** – Counts by interaction type

Content-Type: `application/json`

```json
{
  "ok": true,
  "result": {
    "call": 1,
    "email": 1,
    "meeting": 1,
    "note": 1,
    "task": 1,
    "total": 1
  }
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/interactions/counts?entityId=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/interactions/tasks`

List customertasks

Returns a paginated collection of customertasks scoped to the authenticated organization.

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| all | query | any | Optional |
| entityId | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated customertasks

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "todoId": "string",
      "todoSource": "string",
      "todoTitle": null,
      "todoIsDone": null,
      "todoPriority": null,
      "todoSeverity": null,
      "todoDescription": null,
      "todoDueAt": null,
      "todoCustomValues": null,
      "todoOrganizationId": null,
      "organizationId": "string",
      "tenantId": "string",
      "createdAt": "string",
      "externalHref": null,
      "customer": {
        "id": null,
        "displayName": null,
        "kind": null
      }
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/interactions/tasks?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/labels`

List labels

Returns labels for the current user within the selected organization. Optionally includes assignment status for a specific entity.

**Tags:** Customers

**Requires authentication.**

### Responses

**200** – Labels list

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "slug": "string",
      "label": "string"
    }
  ],
  "assignedIds": [
    "00000000-0000-4000-8000-000000000000"
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/labels" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/labels`

Create label

Creates a new label scoped to the current user and selected organization.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "label": "string"
}
```

### Responses

**201** – Label created

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "slug": "string",
  "label": "string"
}
```

**409** – Duplicate slug

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/customers/labels" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"label\": \"string\"
}"
```

## POST `/customers/labels/assign`

Assign label

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "labelId": "00000000-0000-4000-8000-000000000000",
  "entityId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Already assigned

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

**201** – Assigned

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

**404** – Label or entity not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/customers/labels/assign" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"labelId\": \"00000000-0000-4000-8000-000000000000\",
  \"entityId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## POST `/customers/labels/unassign`

Unassign label

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "labelId": "00000000-0000-4000-8000-000000000000",
  "entityId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Unassigned

Content-Type: `application/json`

```json
{
  "id": null
}
```

**404** – Label or entity not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/customers/labels/unassign" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"labelId\": \"00000000-0000-4000-8000-000000000000\",
  \"entityId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## DELETE `/customers/people`

Delete person

Deletes a person by id. Request body or query may provide the identifier.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Person deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**422** – Person has dependent records (e.g. linked deals); unlink or reassign before delete.

Content-Type: `application/json`

```json
{
  "error": "string",
  "code": "PERSON_HAS_DEPENDENTS"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/customers/people" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/customers/people`

List people

Returns a paginated collection of people scoped to the authenticated organization.

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| email | query | any | Optional |
| emailStartsWith | query | any | Optional |
| emailContains | query | any | Optional |
| status | query | any | Optional |
| lifecycleStage | query | any | Optional |
| source | query | any | Optional |
| hasEmail | query | any | Optional |
| hasPhone | query | any | Optional |
| hasNextInteraction | query | any | Optional |
| createdFrom | query | any | Optional |
| createdTo | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| id | query | any | Optional |
| tagIds | query | any | Optional |
| tagIdsEmpty | query | any | Optional |
| excludeIds | query | any | Optional |
| excludeLinkedCompanyId | query | any | Optional |
| excludeLinkedDealId | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated people

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "description": null,
      "owner_user_id": null,
      "primary_email": null,
      "primary_phone": null,
      "status": null,
      "lifecycle_stage": null,
      "source": null,
      "next_interaction_at": null,
      "next_interaction_name": null,
      "next_interaction_ref_id": null,
      "next_interaction_icon": null,
      "next_interaction_color": null,
      "organization_id": null,
      "tenant_id": null,
      "created_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/people?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/people`

Create person

Creates a person contact using scoped organization and tenant identifiers.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "description": null,
  "primaryEmail": null,
  "primaryPhone": null,
  "nextInteraction": null,
  "firstName": "string",
  "lastName": "string",
  "linkedInUrl": null,
  "twitterUrl": null,
  "companyEntityId": null
}
```

### Responses

**201** – Person created

Content-Type: `application/json`

```json
{
  "id": null,
  "personId": null
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/customers/people" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"description\": null,
  \"primaryEmail\": null,
  \"primaryPhone\": null,
  \"nextInteraction\": null,
  \"firstName\": \"string\",
  \"lastName\": \"string\",
  \"linkedInUrl\": null,
  \"twitterUrl\": null,
  \"companyEntityId\": null
}"
```

## PUT `/customers/people`

Update person

Updates contact details or custom fields for a person.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "description": null,
  "primaryEmail": null,
  "primaryPhone": null,
  "nextInteraction": null,
  "linkedInUrl": null,
  "twitterUrl": null,
  "companyEntityId": null
}
```

### Responses

**200** – Person updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/customers/people" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"description\": null,
  \"primaryEmail\": null,
  \"primaryPhone\": null,
  \"nextInteraction\": null,
  \"linkedInUrl\": null,
  \"twitterUrl\": null,
  \"companyEntityId\": null
}"
```

## GET `/customers/people/{id}`

Fetch person with related data

Returns a person customer record with optional related resources such as addresses, comments, activities, interactions, deals, and todos.

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| include | query | any | Optional. Comma-separated list of relations to include (addresses, comments, activities, interactions, deals, todos). |

### Responses

**200** – Person detail payload

Content-Type: `application/json`

```json
{
  "interactionMode": "canonical",
  "person": {
    "id": "00000000-0000-4000-8000-000000000000",
    "displayName": null,
    "description": null,
    "ownerUserId": null,
    "primaryEmail": null,
    "primaryPhone": null,
    "status": null,
    "lifecycleStage": null,
    "source": null,
    "nextInteractionAt": null,
    "nextInteractionName": null,
    "nextInteractionRefId": null,
    "nextInteractionIcon": null,
    "nextInteractionColor": null,
    "organizationId": null,
    "tenantId": null,
    "createdAt": "string",
    "updatedAt": "string"
  },
  "profile": null,
  "customFields": {},
  "tags": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "label": "string",
      "color": null
    }
  ],
  "addresses": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": null,
      "purpose": null,
      "addressLine1": null,
      "addressLine2": null,
      "buildingNumber": null,
      "flatNumber": null,
      "city": null,
      "region": null,
      "postalCode": null,
      "country": null,
      "latitude": null,
      "longitude": null,
      "isPrimary": null,
      "createdAt": "string"
    }
  ],
  "comments": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "body": null,
      "authorUserId": null,
      "authorName": null,
      "authorEmail": null,
      "dealId": null,
      "createdAt": "string",
      "appearanceIcon": null,
      "appearanceColor": null
    }
  ],
  "activities": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "activityType": "string",
      "subject": null,
      "body": null,
      "occurredAt": null,
      "dealId": null,
      "authorUserId": null,
      "authorName": null,
      "authorEmail": null,
      "createdAt": "string",
      "appearanceIcon": null,
      "appearanceColor": null
    }
  ],
  "interactions": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "entityId": null,
      "interactionType": "string",
      "title": null,
      "body": null,
      "status": "string",
      "scheduledAt": null,
      "occurredAt": null,
      "priority": null,
      "authorUserId": null,
      "ownerUserId": null,
      "dealId": null,
      "organizationId": null,
      "tenantId": null,
      "authorName": null,
      "authorEmail": null,
      "dealTitle": null,
      "customValues": null,
      "appearanceIcon": null,
      "appearanceColor": null,
      "source": null,
      "createdAt": "string",
      "updatedAt": "string"
    }
  ],
  "deals": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "title": null,
      "status": null,
      "pipelineStage": null,
      "valueAmount": null,
      "valueCurrency": null,
      "probability": null,
      "expectedCloseAt": null,
      "ownerUserId": null,
      "source": null,
      "closureOutcome": null,
      "lossReasonId": null,
      "lossNotes": null,
      "createdAt": "string",
      "updatedAt": "string"
    }
  ],
  "todos": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "todoId": "00000000-0000-4000-8000-000000000000",
      "todoSource": "string",
      "createdAt": "string",
      "createdByUserId": null,
      "title": null,
      "isDone": null,
      "priority": null,
      "severity": null,
      "description": null,
      "dueAt": null,
      "todoOrganizationId": null,
      "customValues": null
    }
  ],
  "isPrimary": true,
  "companies": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "displayName": "string",
      "isPrimary": true
    }
  ],
  "viewer": {
    "userId": null,
    "name": null,
    "email": null
  }
}
```

**400** – Invalid identifier

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Forbidden for tenant/organization scope

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Person not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/people/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/people/{id}/companies`

List linked companies for a person

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Linked company rows

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "companyId": "00000000-0000-4000-8000-000000000000",
      "displayName": "string",
      "isPrimary": true
    }
  ]
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/people/:id/companies" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/people/{id}/companies`

Link a company to a person

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "companyId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Linked company row

Content-Type: `application/json`

```json
{
  "ok": true,
  "result": {
    "id": "00000000-0000-4000-8000-000000000000",
    "companyId": "00000000-0000-4000-8000-000000000000",
    "displayName": "string",
    "isPrimary": true
  }
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/customers/people/:id/companies" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"companyId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## DELETE `/customers/people/{id}/companies/{linkId}`

Remove a linked company from a person

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| linkId | path | any | Required |

### Responses

**200** – Deletion result

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/customers/people/:id/companies/:linkId" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PATCH `/customers/people/{id}/companies/{linkId}`

Update a linked company for a person

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| linkId | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Updated company link

Content-Type: `application/json`

```json
{
  "ok": true,
  "result": null
}
```

### Example

```bash
curl -X PATCH "https://demo-carrier.closare.com/api/customers/people/:id/companies/:linkId" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## GET `/customers/people/{id}/companies/enriched`

Get enriched company data for a person's linked companies

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| sort | query | any | Optional |

### Responses

**200** – Enriched company rows with profile, billing, tags, deals and more

Content-Type: `application/json`

```json
{
  "items": [
    {
      "linkId": "00000000-0000-4000-8000-000000000000",
      "companyId": "00000000-0000-4000-8000-000000000000",
      "displayName": "string",
      "isPrimary": true,
      "subtitle": null,
      "profile": null,
      "billing": null,
      "primaryAddress": null,
      "tags": [
        {
          "id": "00000000-0000-4000-8000-000000000000",
          "label": "string",
          "color": null
        }
      ],
      "roles": [
        {
          "id": "00000000-0000-4000-8000-000000000000",
          "roleValue": "string"
        }
      ],
      "activeDeal": null,
      "lastContactAt": null,
      "clv": null,
      "status": null,
      "lifecycleStage": null,
      "temperature": null,
      "renewalQuarter": null
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/people/:id/companies/enriched?page=1&pageSize=20&sort=name-asc" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/people/{id}/email-threads`

List a Person's email threads (Gmail-style conversation grouping)

**Tags:** Customers, Email

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Email threads for the person, grouped by conversation

Content-Type: `application/json`

**400** – Invalid person id

Content-Type: `application/json`

**401** – Unauthorized

Content-Type: `application/json`

**403** – Missing customers.people.view feature

Content-Type: `application/json`

**404** – Person not found

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/people/:id/email-threads" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/people/{id}/emails`

Compose + send an email anchored to a Person

**Tags:** Customers, Email

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Email queued for send

Content-Type: `application/json`

**400** – Invalid person id

Content-Type: `application/json`

**401** – Unauthorized

Content-Type: `application/json`

**403** – Missing customers.email.compose feature or mutation guard rejection

Content-Type: `application/json`

**404** – Person or channel not found

Content-Type: `application/json`

**409** – Channel not connected

Content-Type: `application/json`

**422** – Invalid request body

Content-Type: `application/json`

**500** – Send failed

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/customers/people/:id/emails" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/customers/people/{id}/roles`

Remove a person role assignment

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| roleId | query | any | Required |

### Responses

**200** – Role deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Invalid request

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Role not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/customers/people/00000000-0000-4000-8000-000000000000/roles?roleId=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/customers/people/{id}/roles`

List roles for a person

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Role assignments

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "entityType": "company",
      "entityId": "00000000-0000-4000-8000-000000000000",
      "userId": "00000000-0000-4000-8000-000000000000",
      "userName": null,
      "userEmail": null,
      "userPhone": null,
      "roleType": "string",
      "createdAt": "string",
      "updatedAt": "string"
    }
  ]
}
```

**400** – Invalid request

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/people/00000000-0000-4000-8000-000000000000/roles" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/people/{id}/roles`

Assign a role to a person

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "roleType": "string",
  "userId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**201** – Role created

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

**400** – Invalid request

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**409** – Role already assigned

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/customers/people/00000000-0000-4000-8000-000000000000/roles" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"roleType\": \"string\",
  \"userId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## PUT `/customers/people/{id}/roles`

Update a person role assignment

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| roleId | query | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "userId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Role updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Invalid request

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Role not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/customers/people/00000000-0000-4000-8000-000000000000/roles?roleId=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"userId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/customers/people/check-phone`

Find person by phone digits

Performs an exact digits comparison (stripping non-numeric characters) to determine whether a customer contact matches the provided phone fragment.

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| digits | query | any | Required |

### Responses

**200** – Matching contact (if any)

Content-Type: `application/json`

```json
{
  "match": null
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/people/check-phone" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/customers/pipeline-stages`

Delete pipeline stage

Deletes a pipeline stage. Returns 409 if active deals use this stage.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Stage deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**404** – Stage not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**409** – Stage has active deals

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/customers/pipeline-stages" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/customers/pipeline-stages`

List pipeline stages

Returns pipeline stages for the authenticated organization, optionally filtered by pipelineId.

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| pipelineId | query | any | Optional |

### Responses

**200** – Stage list

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "pipelineId": "00000000-0000-4000-8000-000000000000",
      "label": "string",
      "order": 1,
      "color": null,
      "icon": null,
      "organizationId": "00000000-0000-4000-8000-000000000000",
      "tenantId": "00000000-0000-4000-8000-000000000000",
      "createdAt": "2025-01-01T00:00:00.000Z",
      "updatedAt": "2025-01-01T00:00:00.000Z"
    }
  ],
  "total": 1
}
```

**400** – Invalid request

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/pipeline-stages" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/pipeline-stages`

Create pipeline stage

Creates a new pipeline stage.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "pipelineId": "00000000-0000-4000-8000-000000000000",
  "label": "string",
  "color": null,
  "icon": null
}
```

### Responses

**201** – Stage created

Content-Type: `application/json`

```json
{
  "id": null
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/customers/pipeline-stages" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"pipelineId\": \"00000000-0000-4000-8000-000000000000\",
  \"label\": \"string\",
  \"color\": null,
  \"icon\": null
}"
```

## PUT `/customers/pipeline-stages`

Update pipeline stage

Updates an existing pipeline stage.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "color": null,
  "icon": null
}
```

### Responses

**200** – Stage updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Stage not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/customers/pipeline-stages" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"color\": null,
  \"icon\": null
}"
```

## POST `/customers/pipeline-stages/reorder`

Reorder pipeline stages

Updates the order of pipeline stages in bulk.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "stages": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "order": 1
    }
  ]
}
```

### Responses

**200** – Stages reordered

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/customers/pipeline-stages/reorder" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"stages\": [
    {
      \"id\": \"00000000-0000-4000-8000-000000000000\",
      \"order\": 1
    }
  ]
}"
```

## DELETE `/customers/pipelines`

Delete pipeline

Deletes a pipeline. Returns 409 if active deals exist.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Pipeline deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**404** – Pipeline not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**409** – Pipeline has active deals

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/customers/pipelines" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/customers/pipelines`

List pipelines

Returns a list of pipelines scoped to the authenticated organization.

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| isDefault | query | any | Optional |

### Responses

**200** – Pipeline list

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "isDefault": true,
      "organizationId": "00000000-0000-4000-8000-000000000000",
      "tenantId": "00000000-0000-4000-8000-000000000000",
      "createdAt": "2025-01-01T00:00:00.000Z",
      "updatedAt": "2025-01-01T00:00:00.000Z"
    }
  ],
  "total": 1
}
```

**400** – Invalid request

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/pipelines" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/pipelines`

Create pipeline

Creates a new pipeline within the authenticated organization.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "name": "string"
}
```

### Responses

**201** – Pipeline created

Content-Type: `application/json`

```json
{
  "id": null
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/customers/pipelines" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"name\": \"string\"
}"
```

## PUT `/customers/pipelines`

Update pipeline

Updates an existing pipeline.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Pipeline updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Pipeline not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/customers/pipelines" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/customers/settings/address-format`

Retrieve address format

Returns the current address formatting preference for the selected organization.

**Tags:** Customers

**Requires authentication.**

### Responses

**200** – Current address format

Content-Type: `application/json`

```json
{
  "addressFormat": "string"
}
```

**400** – Organization context missing

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/settings/address-format" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/customers/settings/address-format`

Update address format

Updates the address format preference for the selected organization.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "addressFormat": "line_first"
}
```

### Responses

**200** – Updated address format

Content-Type: `application/json`

```json
{
  "addressFormat": "string"
}
```

**400** – Invalid payload or organization context

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/customers/settings/address-format" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"addressFormat\": \"line_first\"
}"
```

## GET `/customers/settings/dictionary-sort-modes`

Retrieve dictionary sort modes

Returns entry sort preferences for customer dictionaries in the selected organization.

**Tags:** Customers

**Requires authentication.**

### Responses

**200** – Current dictionary sort modes

Content-Type: `application/json`

```json
{
  "dictionarySortModes": {
    "key": "label_asc"
  }
}
```

**400** – Organization context missing

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/settings/dictionary-sort-modes" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PATCH `/customers/settings/dictionary-sort-modes`

Update dictionary sort modes

Updates entry sort preferences for customer dictionaries in the selected organization.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "dictionarySortModes": {
    "key": "label_asc"
  }
}
```

### Responses

**200** – Updated dictionary sort modes

Content-Type: `application/json`

```json
{
  "dictionarySortModes": {
    "key": "label_asc"
  }
}
```

**400** – Invalid payload or organization context

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PATCH "https://demo-carrier.closare.com/api/customers/settings/dictionary-sort-modes" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"dictionarySortModes\": {
    \"key\": \"label_asc\"
  }
}"
```

## GET `/customers/settings/stuck-threshold`

Retrieve stuck-threshold days

Returns the current stuck-deal threshold (in days) for the selected organization.

**Tags:** Customers

**Requires authentication.**

### Responses

**200** – Current threshold

Content-Type: `application/json`

```json
{
  "stuckThresholdDays": 1
}
```

**400** – Organization context missing

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/settings/stuck-threshold" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/customers/settings/stuck-threshold`

Update stuck-threshold days

Updates the stuck-deal threshold for the selected organization.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "stuckThresholdDays": 1
}
```

### Responses

**200** – Updated threshold

Content-Type: `application/json`

```json
{
  "stuckThresholdDays": 1
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/customers/settings/stuck-threshold" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"stuckThresholdDays\": 1
}"
```

## DELETE `/customers/tags`

Delete tag

Deletes a tag identified by `id`. The identifier may be provided via body or query string.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Tag deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/customers/tags" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/customers/tags`

List tags

Returns a paginated collection of tags scoped to the authenticated organization.

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated tags

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "slug": "string",
      "label": "string",
      "color": null,
      "description": null,
      "organization_id": null,
      "tenant_id": null,
      "updated_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/tags?page=1&pageSize=100" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/tags`

Create tag

Creates a tag scoped to the current tenant and organization.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "slug": "string",
  "label": "string"
}
```

### Responses

**201** – Tag created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/customers/tags" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"slug\": \"string\",
  \"label\": \"string\"
}"
```

## PUT `/customers/tags`

Update tag

Updates label, color, or description for an existing tag.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Tag updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/customers/tags" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## POST `/customers/tags/assign`

Assign tag to customer entity

Links a tag to a customer entity within the validated tenant / organization scope.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "tagId": "00000000-0000-4000-8000-000000000000",
  "entityId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**201** – Tag assigned to customer

Content-Type: `application/json`

```json
{
  "id": null
}
```

**400** – Validation or assignment failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Insufficient tenant/organization access

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/customers/tags/assign" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"tagId\": \"00000000-0000-4000-8000-000000000000\",
  \"entityId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## POST `/customers/tags/unassign`

Remove tag from customer entity

Detaches a tag from a customer entity within the validated tenant / organization scope.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "tagId": "00000000-0000-4000-8000-000000000000",
  "entityId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Tag unassigned from customer

Content-Type: `application/json`

```json
{
  "id": null
}
```

**400** – Validation or unassignment failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Insufficient tenant/organization access

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/customers/tags/unassign" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"tagId\": \"00000000-0000-4000-8000-000000000000\",
  \"entityId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## DELETE `/customers/todos`

Delete customertodo

DEPRECATED (sunset 2026-06-30): Deletes a customer task. Use DELETE /api/customers/interactions instead.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – CustomerTodo deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/customers/todos" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/customers/todos`

List customertodos

Returns a paginated collection of customertodos scoped to the authenticated organization.

**Tags:** Customers

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| all | query | any | Optional |
| entityId | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated customertodos

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "todoId": "string",
      "todoSource": "string",
      "todoTitle": null,
      "todoIsDone": null,
      "todoPriority": null,
      "todoSeverity": null,
      "todoDescription": null,
      "todoDueAt": null,
      "todoCustomValues": null,
      "todoOrganizationId": null,
      "todoUpdatedAt": null,
      "organizationId": "string",
      "tenantId": "string",
      "createdAt": "string",
      "externalHref": null,
      "customer": {
        "id": null,
        "displayName": null,
        "kind": null
      }
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/customers/todos?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/todos`

Create customertodo

DEPRECATED (sunset 2026-06-30): Creates a customer task. Use POST /api/customers/interactions instead.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "entityId": "00000000-0000-4000-8000-000000000000",
  "title": "string",
  "todoSource": "customers:interaction"
}
```

### Responses

**201** – CustomerTodo created

Content-Type: `application/json`

```json
{
  "linkId": null,
  "todoId": null
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/customers/todos" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityId\": \"00000000-0000-4000-8000-000000000000\",
  \"title\": \"string\",
  \"todoSource\": \"customers:interaction\"
}"
```

## PUT `/customers/todos`

Update customertodo

DEPRECATED (sunset 2026-06-30): Updates a customer task. Use PUT /api/customers/interactions instead.

**Tags:** Customers

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – CustomerTodo updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/customers/todos" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/dictionaries`

List dictionaries

Returns dictionaries accessible to the current organization, optionally including inactive records.

**Tags:** Dictionaries

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| includeInactive | query | any | Optional |

### Responses

**200** – Dictionary collection.

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "key": "string",
      "name": "string",
      "description": null,
      "isSystem": true,
      "isActive": true,
      "managerVisibility": null,
      "organizationId": null,
      "createdAt": "string",
      "updatedAt": null
    }
  ]
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to load dictionaries

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/dictionaries" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/dictionaries`

Create dictionary

Registers a dictionary scoped to the current organization.

**Tags:** Dictionaries

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "key": "string",
  "name": "string"
}
```

### Responses

**201** – Dictionary created.

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "key": "string",
  "name": "string",
  "description": null,
  "isSystem": true,
  "isActive": true,
  "managerVisibility": null,
  "organizationId": null,
  "createdAt": "string",
  "updatedAt": null
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**409** – Dictionary key already exists

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to create dictionary

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/dictionaries" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"key\": \"string\",
  \"name\": \"string\"
}"
```

## DELETE `/dictionaries/{dictionaryId}`

Delete dictionary

Soft deletes the dictionary unless it is the protected currency dictionary.

**Tags:** Dictionaries

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| dictionaryId | path | any | Required |

### Responses

**200** – Dictionary archived.

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Protected dictionary cannot be deleted

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Dictionary not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to delete dictionary

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/dictionaries/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/dictionaries/{dictionaryId}`

Get dictionary

Returns details for the specified dictionary, including inheritance flags.

**Tags:** Dictionaries

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| dictionaryId | path | any | Required |

### Responses

**200** – Dictionary details.

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "key": "string",
  "name": "string",
  "description": null,
  "isSystem": true,
  "isActive": true,
  "managerVisibility": null,
  "organizationId": null,
  "createdAt": "string",
  "updatedAt": null
}
```

**400** – Invalid parameters

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Dictionary not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to load dictionary

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/dictionaries/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PATCH `/dictionaries/{dictionaryId}`

Update dictionary

Updates mutable attributes of the dictionary. Currency dictionaries are protected from modification.

**Tags:** Dictionaries

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| dictionaryId | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Dictionary updated.

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "key": "string",
  "name": "string",
  "description": null,
  "isSystem": true,
  "isActive": true,
  "managerVisibility": null,
  "organizationId": null,
  "createdAt": "string",
  "updatedAt": null
}
```

**400** – Validation failed or protected dictionary

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Dictionary not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**409** – Dictionary key already exists

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to update dictionary

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PATCH "https://demo-carrier.closare.com/api/dictionaries/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## GET `/dictionaries/{dictionaryId}/entries`

List dictionary entries

Returns entries for the specified dictionary ordered by its configured entry sort mode. The number of entries returned per request is capped at 500; use `limit` and `offset` with the `total`/`hasMore` response fields to page through larger dictionaries.

**Tags:** Dictionaries

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| dictionaryId | path | any | Required |
| limit | query | any | Optional. Maximum entries to return. Defaults to and is capped at 500. |
| offset | query | any | Optional. Number of entries to skip. Defaults to 0. |

### Responses

**200** – Dictionary entries.

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "value": "string",
      "label": "string",
      "color": null,
      "icon": null,
      "position": 1,
      "isDefault": true,
      "createdAt": "string",
      "updatedAt": null
    }
  ],
  "total": 1,
  "limit": 1,
  "offset": 1,
  "hasMore": true,
  "sortMode": "label_asc"
}
```

**400** – Invalid parameters

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Dictionary not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to load dictionary entries

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/dictionaries/00000000-0000-4000-8000-000000000000/entries" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/dictionaries/{dictionaryId}/entries`

Create dictionary entry

Creates a new entry in the specified dictionary.

**Tags:** Dictionaries

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| dictionaryId | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "value": "string",
  "color": null,
  "icon": null
}
```

### Responses

**201** – Dictionary entry created.

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "value": "string",
  "label": "string",
  "color": null,
  "icon": null,
  "position": 1,
  "isDefault": true,
  "createdAt": "string",
  "updatedAt": null
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Dictionary not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to create dictionary entry

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/dictionaries/00000000-0000-4000-8000-000000000000/entries" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"value\": \"string\",
  \"color\": null,
  \"icon\": null
}"
```

## DELETE `/dictionaries/{dictionaryId}/entries/{entryId}`

Delete dictionary entry

Deletes the specified dictionary entry via the command bus.

**Tags:** Dictionaries

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| dictionaryId | path | any | Required |
| entryId | path | any | Required |

### Responses

**200** – Entry deleted.

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Dictionary or entry not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to delete entry

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/dictionaries/00000000-0000-4000-8000-000000000000/entries/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PATCH `/dictionaries/{dictionaryId}/entries/{entryId}`

Update dictionary entry

Updates the specified dictionary entry using the command bus pipeline.

**Tags:** Dictionaries

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| dictionaryId | path | any | Required |
| entryId | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "color": null,
  "icon": null
}
```

### Responses

**200** – Dictionary entry updated.

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "value": "string",
  "label": "string",
  "color": null,
  "icon": null,
  "position": 1,
  "isDefault": true,
  "createdAt": "string",
  "updatedAt": null
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Dictionary or entry not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to update entry

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PATCH "https://demo-carrier.closare.com/api/dictionaries/00000000-0000-4000-8000-000000000000/entries/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"color\": null,
  \"icon\": null
}"
```

## POST `/dictionaries/{dictionaryId}/entries/reorder`

Reorder dictionary entries

Updates the position of dictionary entries for drag-and-drop reordering.

**Tags:** Dictionaries

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| dictionaryId | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "entries": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "position": 1
    }
  ]
}
```

### Responses

**200** – Entries reordered.

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Dictionary not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to reorder entries

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/dictionaries/00000000-0000-4000-8000-000000000000/entries/reorder" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entries\": [
    {
      \"id\": \"00000000-0000-4000-8000-000000000000\",
      \"position\": 1
    }
  ]
}"
```

## POST `/dictionaries/{dictionaryId}/entries/set-default`

Set default dictionary entry

Marks the specified entry as the default for this dictionary, clearing any previous default.

**Tags:** Dictionaries

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| dictionaryId | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "entryId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Default entry set.

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Dictionary or entry not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Failed to set default entry

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/dictionaries/00000000-0000-4000-8000-000000000000/entries/set-default" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entryId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/directory/organization-branding`

Read sidebar branding for the selected organization

Returns the logo URL used by the backend sidebar for the currently selected organization.

**Tags:** Directory

**Requires authentication.**

### Responses

**200** – Organization branding

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "organizationName": "string",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "logoUrl": null,
  "logoPreserveAspectRatio": true,
  "updatedAt": null
}
```

**400** – A concrete organization scope is required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Organization not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/directory/organization-branding" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/directory/organization-branding`

Update sidebar branding for the selected organization

Stores an external image URL or an internal attachment image URL as the selected organization logo.

**Tags:** Directory

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "logoUrl": null
}
```

### Responses

**200** – Updated organization branding

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "organizationName": "string",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "logoUrl": null,
  "logoPreserveAspectRatio": true,
  "updatedAt": null
}
```

**400** – Save failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**409** – Organization branding changed since it was loaded

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**422** – Invalid logo URL

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/directory/organization-branding" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"logoUrl\": null
}"
```

## GET `/directory/organization-switcher`

Load organization switcher menu

Returns the hierarchical menu of organizations the current user may switch to within the active tenant.

**Tags:** Directory

**Requires authentication.**

### Responses

**200** – Organization switcher payload.

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "depth": 1,
      "selectable": true,
      "children": []
    }
  ],
  "selectedId": null,
  "canManage": true,
  "canViewAllOrganizations": true,
  "tenantId": null,
  "tenants": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "isActive": true
    }
  ],
  "isSuperAdmin": true
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/directory/organization-switcher" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/directory/organizations`

Delete organization

Soft deletes an organization identified by id.

**Tags:** Directory

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Organization deleted.

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Missing directory.organizations.manage feature

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/directory/organizations" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/directory/organizations`

List organizations

Returns organizations using options, tree, or paginated manage view depending on the `view` parameter.

**Tags:** Directory

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| view | query | any | Optional |
| ids | query | any | Optional |
| tenantId | query | any | Optional |
| includeInactive | query | any | Optional |
| status | query | any | Optional |

### Responses

**200** – Organization data for the requested view.

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "parentId": null,
      "parentName": null,
      "tenantId": null,
      "tenantName": null,
      "rootId": null,
      "treePath": null
    }
  ]
}
```

**400** – Invalid query or tenant scope

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/directory/organizations?page=1&pageSize=50&view=options" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/directory/organizations`

Create organization

Creates a new organization within a tenant and optionally assigns hierarchy relationships.

**Tags:** Directory

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "name": "string",
  "slug": null,
  "logoUrl": null,
  "parentId": null
}
```

### Responses

**201** – Organization created.

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Missing directory.organizations.manage feature

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/directory/organizations" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"name\": \"string\",
  \"slug\": null,
  \"logoUrl\": null,
  \"parentId\": null
}"
```

## PUT `/directory/organizations`

Update organization

Updates organization details and hierarchy assignments.

**Tags:** Directory

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "slug": null,
  "logoUrl": null,
  "parentId": null
}
```

### Responses

**200** – Organization updated.

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Missing directory.organizations.manage feature

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/directory/organizations" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"slug\": null,
  \"logoUrl\": null,
  \"parentId\": null
}"
```

## GET `/directory/organizations/lookup`

Public organization lookup by slug

**Tags:** Directory (Tenants & Organizations)

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/directory/organizations/lookup" \
  -H "Accept: application/json"
```

## DELETE `/directory/tenants`

Delete tenant

Soft deletes the tenant identified by id.

**Tags:** Directory

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Tenant removed.

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Missing directory.tenants.manage feature

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/directory/tenants" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/directory/tenants`

List tenants

Returns tenants visible to the current user with optional search and pagination.

**Tags:** Directory

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | query | any | Optional |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| isActive | query | any | Optional |

### Responses

**200** – Paged list of tenants.

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "isActive": true,
      "createdAt": null,
      "updatedAt": null
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

**400** – Invalid query parameters

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Requires super-admin

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/directory/tenants?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/directory/tenants`

Create tenant

Creates a new tenant and returns its identifier.

**Tags:** Directory

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "name": "string"
}
```

### Responses

**201** – Tenant created.

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Missing directory.tenants.manage feature

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/directory/tenants" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"name\": \"string\"
}"
```

## PUT `/directory/tenants`

Update tenant

Updates tenant properties such as name or activation state.

**Tags:** Directory

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Tenant updated.

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Missing directory.tenants.manage feature

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/directory/tenants" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/directory/tenants/lookup`

Public tenant lookup

**Tags:** Directory (Tenants & Organizations)

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/directory/tenants/lookup" \
  -H "Accept: application/json"
```

## DELETE `/entities/definitions`

Soft delete custom field definition

Marks the specified definition inactive and tombstones it for the current scope.

**Tags:** Entities

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "entityId": "string",
  "key": "string"
}
```

### Responses

**200** – Definition deleted

Content-Type: `application/json`

```json
{
  "ok": true,
  "version": null
}
```

**400** – Missing entity id or key

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Missing authentication

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Definition not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/entities/definitions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityId\": \"string\",
  \"key\": \"string\"
}"
```

## GET `/entities/definitions`

List active custom field definitions

Returns active custom field definitions for the supplied entity ids, respecting tenant scope and tombstones.

**Tags:** Entities

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| entityId | query | any | Optional |
| entityIds | query | any | Optional |
| fieldset | query | any | Optional |

### Responses

**200** – Definition list

Content-Type: `application/json`

```json
{
  "items": [
    {
      "key": "string",
      "kind": "string",
      "label": "string",
      "entityId": "string"
    }
  ]
}
```

**400** – Missing entity id

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Missing authentication

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/entities/definitions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/entities/definitions`

Upsert custom field definition

Creates or updates a custom field definition for the current tenant/org scope.

**Tags:** Entities

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "entityId": "string",
  "key": "string",
  "kind": "text"
}
```

### Responses

**200** – Definition saved

Content-Type: `application/json`

```json
{
  "ok": true,
  "item": {
    "id": "00000000-0000-4000-8000-000000000000",
    "key": "string",
    "kind": "string",
    "configJson": {}
  }
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Missing authentication

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/entities/definitions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityId\": \"string\",
  \"key\": \"string\",
  \"kind\": \"text\"
}"
```

## POST `/entities/definitions.batch`

Save multiple custom field definitions

Creates or updates multiple definitions for a single entity in one transaction.

**Tags:** Entities

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "entityId": "string",
  "definitions": [
    {
      "key": "string",
      "kind": "text"
    }
  ]
}
```

### Responses

**200** – Definitions saved

Content-Type: `application/json`

```json
{
  "ok": true,
  "version": null
}
```

**400** – Validation error

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Missing authentication

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Unexpected failure

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/entities/definitions.batch" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityId\": \"string\",
  \"definitions\": [
    {
      \"key\": \"string\",
      \"kind\": \"text\"
    }
  ]
}"
```

## GET `/entities/definitions.manage`

Get management snapshot

Returns scoped custom field definitions (including inactive tombstones) for administration interfaces.

**Tags:** Entities

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| entityId | query | any | Required |

### Responses

**200** – Scoped definitions and deleted keys

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "key": "string",
      "kind": "string",
      "configJson": null,
      "organizationId": null,
      "tenantId": null
    }
  ],
  "deletedKeys": [
    "string"
  ],
  "version": null
}
```

**400** – Missing entity id

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Missing authentication or feature

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/entities/definitions.manage?entityId=string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/entities/definitions.restore`

Restore definition

Reactivates a previously soft-deleted definition within the current tenant/org scope.

**Tags:** Entities

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "entityId": "string",
  "key": "string"
}
```

### Responses

**200** – Definition restored

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Missing entity id or key

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Missing authentication

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Definition not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/entities/definitions.restore" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityId\": \"string\",
  \"key\": \"string\"
}"
```

## GET `/entities/encryption`

Fetch encryption map

Returns the encrypted field map for the current tenant/organization scope.

**Tags:** Entities

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| entityId | query | any | Required |

### Responses

**200** – Map

Content-Type: `application/json`

```json
{
  "entityId": "string",
  "fields": [
    {
      "field": "string",
      "hashField": null
    }
  ],
  "updatedAt": null
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/entities/encryption?entityId=string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/entities/encryption`

Upsert encryption map

Creates or updates the encryption map for the current tenant/organization scope. Enforces optimistic locking when the caller sends the expected version header.

**Tags:** Entities

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "entityId": "string",
  "tenantId": null,
  "organizationId": null,
  "fields": [
    {
      "field": "string",
      "hashField": null
    }
  ]
}
```

### Responses

**200** – Saved

Content-Type: `application/json`

```json
{
  "ok": true,
  "updatedAt": null
}
```

**409** – Optimistic-lock conflict (stale write)

Content-Type: `application/json`

```json
{
  "error": "string",
  "code": "string",
  "currentUpdatedAt": "string",
  "expectedUpdatedAt": "string"
}
```

**422** – Selected organization is unavailable

Content-Type: `application/json`

```json
{
  "error": "string",
  "code": "organization_selection_invalid"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/entities/encryption" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityId\": \"string\",
  \"tenantId\": null,
  \"organizationId\": null,
  \"fields\": [
    {
      \"field\": \"string\",
      \"hashField\": null
    }
  ]
}"
```

## DELETE `/entities/entities`

Soft delete custom entity

Marks the specified custom entity inactive within the current scope.

**Tags:** Entities

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "entityId": "string"
}
```

### Responses

**200** – Entity deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Missing entity id

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Missing authentication

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Entity not found in scope

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/entities/entities" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityId\": \"string\"
}"
```

## GET `/entities/entities`

List available entities

Returns generated and custom entities scoped to the caller with field counts per entity.

**Tags:** Entities

**Requires authentication.**

### Responses

**200** – List of entities

Content-Type: `application/json`

```json
{
  "items": [
    {
      "entityId": "string",
      "source": "code",
      "label": "string",
      "count": 1
    }
  ]
}
```

**401** – Missing authentication

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/entities/entities" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/entities/entities`

Upsert custom entity

Creates or updates a tenant/org scoped custom entity definition.

**Tags:** Entities

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "entityId": "string",
  "label": "string",
  "description": null,
  "showInSidebar": false,
  "accessRestricted": false
}
```

### Responses

**200** – Entity saved

Content-Type: `application/json`

```json
{
  "ok": true,
  "item": {
    "id": "00000000-0000-4000-8000-000000000000",
    "entityId": "string",
    "label": "string"
  }
}
```

**400** – Validation error

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Missing authentication

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/entities/entities" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityId\": \"string\",
  \"label\": \"string\",
  \"description\": null,
  \"showInSidebar\": false,
  \"accessRestricted\": false
}"
```

## GET `/entities/entity-settings`

Get custom entity settings

Returns the tenant-scoped default-restricted policy for new custom entities.

**Tags:** Entities

**Requires authentication.**

### Responses

**200** – Current settings

Content-Type: `application/json`

```json
{
  "newEntitiesRestrictedByDefault": true,
  "updatedAt": null
}
```

**401** – Missing authentication

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/entities/entity-settings" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/entities/entity-settings`

Update custom entity settings

Sets the tenant-scoped default-restricted policy for new custom entities.

**Tags:** Entities

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "newEntitiesRestrictedByDefault": true
}
```

### Responses

**200** – Updated settings

Content-Type: `application/json`

```json
{
  "ok": true,
  "newEntitiesRestrictedByDefault": true,
  "updatedAt": null
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Missing authentication

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**409** – Optimistic lock conflict

Content-Type: `application/json`

```json
{
  "code": "string",
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/entities/entity-settings" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"newEntitiesRestrictedByDefault\": true
}"
```

## DELETE `/entities/records`

Delete record

Soft deletes the specified record within the current tenant/org scope.

**Tags:** Entities

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "entityId": "string",
  "recordId": "string"
}
```

### Responses

**200** – Record deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Missing entity id or record id

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Missing authentication

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Record not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Unexpected failure

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/entities/records" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityId\": \"string\",
  \"recordId\": \"string\"
}"
```

## GET `/entities/records`

List records

Returns paginated records for the supplied entity. Supports custom field filters, exports, and soft-delete toggles.

**Tags:** Entities

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| entityId | query | any | Required |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| search | query | any | Optional |
| searchFields | query | any | Optional |
| withDeleted | query | any | Optional |
| format | query | any | Optional |
| exportScope | query | any | Optional |
| export_scope | query | any | Optional |
| all | query | any | Optional |
| full | query | any | Optional |

### Responses

**200** – Paginated records

Content-Type: `application/json`

```json
{
  "items": [
    {}
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

**400** – Missing entity id

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Missing authentication

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Unexpected failure

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/entities/records?entityId=string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/entities/records`

Create record

Creates a record for the given entity. When `recordId` is omitted or not a UUID the data engine will generate one automatically.

**Tags:** Entities

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "entityId": "string",
  "values": {}
}
```

### Responses

**200** – Record created

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Validation failure

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Missing authentication

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Unexpected failure

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/entities/records" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityId\": \"string\",
  \"values\": {}
}"
```

## PUT `/entities/records`

Update record

Updates an existing record. If the provided recordId is not a UUID the record will be created instead to support optimistic flows.

**Tags:** Entities

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "entityId": "string",
  "recordId": "string",
  "values": {}
}
```

### Responses

**200** – Record updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Validation failure

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Missing authentication

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Unexpected failure

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/entities/records" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityId\": \"string\",
  \"recordId\": \"string\",
  \"values\": {}
}"
```

## GET `/entities/relations/options`

List relation options

Returns up to 200 option entries for populating relation dropdowns, automatically resolving label fields when omitted. An entityId that matches neither an active custom entity nor a registered ORM entity yields an empty option list.

**Tags:** Entities

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| entityId | query | any | Required |
| labelField | query | any | Optional |
| q | query | any | Optional |
| ids | query | any | Optional |
| routeContextFields | query | any | Optional |

### Responses

**200** – Option list

Content-Type: `application/json`

```json
{
  "items": [
    {
      "value": "string",
      "label": "string"
    }
  ]
}
```

**401** – Missing authentication

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/entities/relations/options?entityId=string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/entities/sidebar-entities`

Get sidebar entities

Returns custom entities flagged with `showInSidebar` for the current tenant/org scope.

**Tags:** Entities

**Requires authentication.**

### Responses

**200** – Sidebar entities for navigation

Content-Type: `application/json`

```json
{
  "items": [
    {
      "entityId": "string",
      "label": "string",
      "href": "string"
    }
  ]
}
```

**401** – Missing authentication

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/entities/sidebar-entities" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/events`

List declared events

Returns every declared event. Filters: category, module, excludeTriggerExcluded (default true).

**Tags:** Events

**Requires authentication.**

### Responses

**200** – Declared events

Content-Type: `application/json`

```json
{
  "data": [
    {
      "id": "string",
      "label": "string"
    }
  ],
  "total": 1
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/events" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/events/stream`

GET /events/stream

**Tags:** Events

**Requires authentication.**

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/events/stream" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/feature_toggles/check/boolean`

Check if feature is enabled

Checks if a feature toggle is enabled for the current context.

**Tags:** Feature Toggles

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| identifier | query | any | Required. Feature toggle identifier |

### Responses

**200** – Feature status

Content-Type: `application/json`

```json
{
  "enabled": true,
  "source": "override",
  "toggleId": "string",
  "identifier": "string",
  "tenantId": "string"
}
```

**400** – Bad Request

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Tenant not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/feature_toggles/check/boolean?identifier=string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/feature_toggles/check/json`

Get json config

Gets the json configuration for a feature toggle.

**Tags:** Feature Toggles

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| identifier | query | any | Required. Feature toggle identifier |

### Responses

**200** – Json config

Content-Type: `application/json`

```json
{
  "valueType": "json",
  "source": "override",
  "toggleId": "string",
  "identifier": "string",
  "tenantId": "string"
}
```

**400** – Bad Request

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Tenant not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/feature_toggles/check/json?identifier=string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/feature_toggles/check/number`

Get number config

Gets the number configuration for a feature toggle.

**Tags:** Feature Toggles

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| identifier | query | any | Required. Feature toggle identifier |

### Responses

**200** – Number config

Content-Type: `application/json`

```json
{
  "valueType": "number",
  "value": 1,
  "source": "override",
  "toggleId": "string",
  "identifier": "string",
  "tenantId": "string"
}
```

**400** – Bad Request

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Tenant not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/feature_toggles/check/number?identifier=string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/feature_toggles/check/string`

Get string config

Gets the string configuration for a feature toggle.

**Tags:** Feature Toggles

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| identifier | query | any | Required. Feature toggle identifier |

### Responses

**200** – String config

Content-Type: `application/json`

```json
{
  "valueType": "string",
  "value": "string",
  "source": "override",
  "toggleId": "string",
  "identifier": "string",
  "tenantId": "string"
}
```

**400** – Bad Request

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Tenant not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/feature_toggles/check/string?identifier=string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/feature_toggles/global`

Delete global feature toggle

Soft deletes a global feature toggle by ID. Requires superadmin role.

**Tags:** Feature Toggles

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | query | any | Required. Feature toggle identifier |

### Responses

**200** – Feature toggle deleted

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

**400** – Invalid identifier

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Forbidden - superadmin role required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Feature toggle not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/feature_toggles/global?id=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/feature_toggles/global`

List global feature toggles

Returns all global feature toggles with filtering and pagination. Requires superadmin role.

**Tags:** Feature Toggles

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional. Page number for pagination |
| pageSize | query | any | Optional. Number of items per page (max 200) |
| search | query | any | Optional. Case-insensitive search across identifier, name, description, and category |
| type | query | any | Optional. Filter by toggle type (boolean, string, number, json) |
| category | query | any | Optional. Filter by category (case-insensitive partial match) |
| name | query | any | Optional. Filter by name (case-insensitive partial match) |
| identifier | query | any | Optional. Filter by identifier (case-insensitive partial match) |
| sortField | query | any | Optional. Field to sort by |
| sortDir | query | any | Optional. Sort direction (ascending or descending) |

### Responses

**200** – Feature toggles collection

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "identifier": "string",
      "name": "string",
      "description": null,
      "category": null,
      "type": "boolean",
      "defaultValue": null,
      "createdAt": null,
      "updatedAt": null
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

**400** – Invalid query parameters

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Forbidden - superadmin role required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/feature_toggles/global?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/feature_toggles/global`

Create global feature toggle

Creates a new global feature toggle. Requires superadmin role.

**Tags:** Feature Toggles

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "identifier": "string",
  "name": "string",
  "description": null,
  "category": null,
  "type": "boolean",
  "defaultValue": null
}
```

### Responses

**201** – Feature toggle created

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Forbidden - superadmin role required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/feature_toggles/global" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"identifier\": \"string\",
  \"name\": \"string\",
  \"description\": null,
  \"category\": null,
  \"type\": \"boolean\",
  \"defaultValue\": null
}"
```

## PUT `/feature_toggles/global`

Update global feature toggle

Updates an existing global feature toggle. Requires superadmin role.

**Tags:** Feature Toggles

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "description": null,
  "category": null,
  "defaultValue": null
}
```

### Responses

**200** – Feature toggle updated

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

**400** – Invalid payload

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Forbidden - superadmin role required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Feature toggle not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/feature_toggles/global" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"description\": null,
  \"category\": null,
  \"defaultValue\": null
}"
```

## GET `/feature_toggles/global/{id}`

Fetch feature toggle by ID

Returns complete details of a feature toggle.

**Tags:** Feature Toggles

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Feature toggle detail

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "identifier": "string",
  "name": "string",
  "description": null,
  "category": null,
  "type": "boolean",
  "defaultValue": null,
  "createdAt": null,
  "updatedAt": null
}
```

**400** – Invalid identifier

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Feature toggle not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/feature_toggles/global/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/feature_toggles/global/{id}/override`

Fetch feature toggle override

Returns feature toggle override.

**Tags:** Feature Toggles

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Feature toggle overrides

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "tenantName": "string",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "toggleType": "boolean",
  "updatedAt": null
}
```

**400** – Invalid request

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Feature toggle not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/feature_toggles/global/:id/override" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/feature_toggles/overrides`

List overrides

Returns list of feature toggle overrides.

**Tags:** Feature Toggles

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| category | query | any | Optional |
| name | query | any | Optional |
| identifier | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| page | query | any | Optional |
| pageSize | query | any | Optional |

### Responses

**200** – List of overrides

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "toggleId": "00000000-0000-4000-8000-000000000000",
      "tenantName": "string",
      "tenantId": "00000000-0000-4000-8000-000000000000",
      "identifier": "string",
      "name": "string",
      "category": "string",
      "isOverride": true
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1,
  "isSuperAdmin": true
}
```

**400** – Invalid query parameters

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/feature_toggles/overrides?page=1&pageSize=25" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/feature_toggles/overrides`

Change override state

Enable, disable or inherit a feature toggle for a specific tenant.

**Tags:** Feature Toggles

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "toggleId": "00000000-0000-4000-8000-000000000000",
  "isOverride": true
}
```

### Responses

**200** – Override updated

Content-Type: `application/json`

```json
{
  "ok": true,
  "overrideToggleId": null
}
```

**400** – Validation failed

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Internal server error

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/feature_toggles/overrides" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"toggleId\": \"00000000-0000-4000-8000-000000000000\",
  \"isOverride\": true
}"
```

## GET `/integrations`

List integrations

Returns a paginated collection of integrations.

**Tags:** Integrations

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| q | query | any | Optional |
| category | query | any | Optional |
| bundleId | query | any | Optional |
| isEnabled | query | any | Optional |
| healthStatus | query | any | Optional |
| sort | query | any | Optional |
| order | query | any | Optional |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated integrations

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "title": "string",
      "description": null,
      "category": null,
      "tags": [
        "string"
      ],
      "hub": null,
      "providerKey": null,
      "bundleId": null,
      "author": null,
      "company": null,
      "version": null,
      "hasCredentials": true,
      "isEnabled": true,
      "apiVersion": null,
      "healthStatus": "healthy",
      "lastHealthCheckedAt": null,
      "lastHealthLatencyMs": null,
      "enabledAt": null,
      "analytics": {
        "lastActivityAt": null,
        "totalCount": 1,
        "errorCount": 1,
        "errorRate": 1,
        "dailyCounts": [
          1
        ]
      }
    }
  ],
  "total": 1,
  "totalPages": 1,
  "bundles": [
    {
      "id": "string",
      "title": "string",
      "description": "string",
      "icon": null,
      "integrationCount": 1,
      "enabledCount": 1
    }
  ]
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/integrations?order=asc&page=1&pageSize=100" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/integrations/{id}`

Get integration detail

**Tags:** Integrations

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/integrations/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/integrations/{id}/credentials`

Get or save integration credentials

**Tags:** Integrations

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/integrations/:id/credentials" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/integrations/{id}/credentials`

Get or save integration credentials

**Tags:** Integrations

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/integrations/:id/credentials" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/integrations/{id}/health`

Run health check for an integration

**Tags:** Integrations

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/integrations/:id/health" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/integrations/{id}/state`

Update integration state

**Tags:** Integrations

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/integrations/:id/state" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/integrations/{id}/version`

Change integration API version

**Tags:** Integrations

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/integrations/:id/version" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/integrations/logs`

List integration logs

**Tags:** Integrations

**Requires authentication.**

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/integrations/logs" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/messages`

List messages

**Tags:** Messages

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| folder | query | any | Optional |
| status | query | any | Optional |
| type | query | any | Optional |
| visibility | query | any | Optional |
| sourceEntityType | query | any | Optional |
| sourceEntityId | query | any | Optional |
| externalEmail | query | any | Optional |
| hasObjects | query | any | Optional |
| hasAttachments | query | any | Optional |
| hasActions | query | any | Optional |
| senderId | query | any | Optional |
| search | query | any | Optional |
| since | query | any | Optional |
| page | query | any | Optional |
| pageSize | query | any | Optional |

### Responses

**200** – Message list

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "type": "string",
      "visibility": null,
      "sourceEntityType": null,
      "sourceEntityId": null,
      "externalEmail": null,
      "externalName": null,
      "subject": "string",
      "bodyPreview": "string",
      "senderUserId": "00000000-0000-4000-8000-000000000000",
      "senderName": null,
      "senderEmail": null,
      "priority": "string",
      "status": "string",
      "hasObjects": true,
      "objectCount": 1,
      "hasAttachments": true,
      "attachmentCount": 1,
      "recipientCount": 1,
      "hasActions": true,
      "actionTaken": null,
      "sentAt": null,
      "readAt": null,
      "threadId": null
    }
  ],
  "page": 1,
  "pageSize": 1,
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/messages?folder=inbox&page=1&pageSize=20" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/messages`

Compose a message

**Tags:** Messages

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "type": "default",
  "visibility": null,
  "recipients": [],
  "subject": "",
  "body": "",
  "bodyFormat": "text",
  "priority": "normal",
  "sendViaEmail": false,
  "isDraft": false
}
```

### Responses

**201** – Message created

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "threadId": null
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/messages" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"type\": \"default\",
  \"visibility\": null,
  \"recipients\": [],
  \"subject\": \"\",
  \"body\": \"\",
  \"bodyFormat\": \"text\",
  \"priority\": \"normal\",
  \"sendViaEmail\": false,
  \"isDraft\": false
}"
```

## DELETE `/messages/{id}`

Delete message for current sender/recipient context

**Tags:** Messages

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Message deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**403** – Access denied

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Message not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**409** – Message was modified concurrently (optimistic lock conflict)

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/messages/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/messages/{id}`

Get message detail

**Tags:** Messages

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Message detail with actor-visible thread items only

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "updatedAt": null,
  "type": "string",
  "isDraft": true,
  "canEditDraft": true,
  "canArchive": true,
  "isArchived": true,
  "visibility": null,
  "sourceEntityType": null,
  "sourceEntityId": null,
  "externalEmail": null,
  "externalName": null,
  "typeDefinition": {
    "labelKey": "string",
    "icon": "string",
    "color": null,
    "allowReply": true,
    "allowForward": true,
    "ui": null
  },
  "threadId": null,
  "parentMessageId": null,
  "senderUserId": "00000000-0000-4000-8000-000000000000",
  "senderName": null,
  "senderEmail": null,
  "subject": "string",
  "body": "string",
  "bodyFormat": "text",
  "priority": "string",
  "sentAt": null,
  "actionData": null,
  "actionTaken": null,
  "actionTakenAt": null,
  "actionTakenByUserId": null,
  "recipients": [
    {
      "userId": "00000000-0000-4000-8000-000000000000",
      "type": "to",
      "status": "string",
      "readAt": null
    }
  ],
  "objects": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "entityModule": "string",
      "entityType": "string",
      "entityId": "00000000-0000-4000-8000-000000000000",
      "actionRequired": true,
      "actionType": null,
      "actionLabel": null,
      "snapshot": null,
      "preview": null
    }
  ],
  "thread": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "senderUserId": "00000000-0000-4000-8000-000000000000",
      "senderName": null,
      "senderEmail": null,
      "body": "string",
      "sentAt": null
    }
  ],
  "isRead": true,
  "conversationArchived": true,
  "conversationAllUnread": true
}
```

**403** – Access denied

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Message not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/messages/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PATCH `/messages/{id}`

Update draft message

**Tags:** Messages

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "visibility": null
}
```

### Responses

**200** – Draft updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**403** – Access denied

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Message not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**409** – Only drafts can be edited, or the draft was modified concurrently (optimistic lock conflict)

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PATCH "https://demo-carrier.closare.com/api/messages/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"visibility\": null
}"
```

## POST `/messages/{id}/actions/{actionId}`

Execute message action

**Tags:** Messages

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| actionId | path | any | Required |

### Request Body

Content-Type: `application/json`

No example available for this content type.

### Responses

**200** – Action executed

Content-Type: `application/json`

```json
{
  "ok": true,
  "actionId": "string"
}
```

**403** – Access denied

Content-Type: `application/json`

**404** – Action not found

Content-Type: `application/json`

**409** – Action already taken, or the message was modified concurrently (optimistic lock conflict)

Content-Type: `application/json`

**410** – Action expired

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/messages/:id/actions/:actionId" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/messages/{id}/archive`

Unarchive message

**Tags:** Messages

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Message unarchived

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**403** – Access denied or sender-only message cannot be unarchived

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Message not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/messages/:id/archive" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/messages/{id}/archive`

Archive message

**Tags:** Messages

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Message archived

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**403** – Access denied or sender-only message cannot be archived

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Message not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/messages/:id/archive" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/messages/{id}/attachments`

Unlink attachments from draft message

**Tags:** Messages

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Attachments unlinked

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**403** – Access denied

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Message not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**409** – Only draft messages can be edited

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/messages/:id/attachments" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## GET `/messages/{id}/attachments`

List message attachments

**Tags:** Messages

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Attachments

Content-Type: `application/json`

```json
{
  "attachments": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "fileName": "string",
      "fileSize": 1,
      "mimeType": "string",
      "url": "string"
    }
  ]
}
```

**403** – Access denied

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Message not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/messages/:id/attachments" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/messages/{id}/attachments`

Link attachments to draft message

**Tags:** Messages

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "attachmentIds": [
    "00000000-0000-4000-8000-000000000000"
  ]
}
```

### Responses

**200** – Attachments linked

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**403** – Access denied

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Message not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**409** – Only draft messages can be edited

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/messages/:id/attachments" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"attachmentIds\": [
    \"00000000-0000-4000-8000-000000000000\"
  ]
}"
```

## GET `/messages/{id}/confirmation`

Read message confirmation status

**Tags:** Messages

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Confirmation status

Content-Type: `application/json`

```json
{
  "messageId": "00000000-0000-4000-8000-000000000000",
  "confirmed": true,
  "confirmedAt": null,
  "confirmedByUserId": null
}
```

**403** – Access denied

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Message not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/messages/:id/confirmation" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/messages/{id}/conversation`

Delete conversation for current actor

**Tags:** Messages

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Conversation deleted

Content-Type: `application/json`

```json
{
  "ok": true,
  "affectedCount": 1
}
```

**403** – Access denied

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Message not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/messages/:id/conversation" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/messages/{id}/conversation/archive`

Unarchive conversation for current actor

**Tags:** Messages

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Conversation unarchived

Content-Type: `application/json`

```json
{
  "ok": true,
  "affectedCount": 1
}
```

**403** – Access denied

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Message not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/messages/:id/conversation/archive" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/messages/{id}/conversation/archive`

Archive conversation for current actor

**Tags:** Messages

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Conversation archived

Content-Type: `application/json`

```json
{
  "ok": true,
  "affectedCount": 1
}
```

**403** – Access denied

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Message not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/messages/:id/conversation/archive" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/messages/{id}/conversation/read`

Mark entire conversation as unread for current actor

**Tags:** Messages

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Conversation marked unread

Content-Type: `application/json`

```json
{
  "ok": true,
  "affectedCount": 1
}
```

**403** – Access denied

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Message not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/messages/:id/conversation/read" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/messages/{id}/conversation/read`

Mark entire conversation as read for current actor

**Tags:** Messages

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Conversation marked read

Content-Type: `application/json`

```json
{
  "ok": true,
  "affectedCount": 1
}
```

**403** – Access denied

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Message not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/messages/:id/conversation/read" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/messages/{id}/forward`

Forward a message and optionally include attachments from the forwarded conversation slice

**Tags:** Messages

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "recipients": [
    {
      "userId": "00000000-0000-4000-8000-000000000000",
      "type": "to"
    }
  ],
  "includeAttachments": true,
  "sendViaEmail": false
}
```

### Responses

**201** – Message forwarded

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

**403** – Access denied

Content-Type: `application/json`

**404** – Message not found

Content-Type: `application/json`

**409** – Forward not allowed for message type

Content-Type: `application/json`

**413** – Forward body exceeds maximum length

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/messages/:id/forward" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"recipients\": [
    {
      \"userId\": \"00000000-0000-4000-8000-000000000000\",
      \"type\": \"to\"
    }
  ],
  \"includeAttachments\": true,
  \"sendViaEmail\": false
}"
```

## GET `/messages/{id}/forward-preview`

Get forward preview for a message

**Tags:** Messages

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Forward preview generated

Content-Type: `application/json`

```json
{
  "subject": "string",
  "body": "string"
}
```

**403** – Access denied

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Message not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**413** – Forward body exceeds maximum length

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/messages/:id/forward-preview" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/messages/{id}/read`

Mark message as unread

**Tags:** Messages

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Message marked unread

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**403** – Access denied

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Message not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/messages/:id/read" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/messages/{id}/read`

Mark message as read

**Tags:** Messages

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Message marked read

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**403** – Access denied

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Message not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/messages/:id/read" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/messages/{id}/reply`

Reply to message

**Tags:** Messages

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "body": "string",
  "bodyFormat": "text",
  "replyAll": false,
  "sendViaEmail": false
}
```

### Responses

**201** – Reply created

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

**403** – Access denied

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Message not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**409** – No recipients available for reply

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/messages/:id/reply" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"body\": \"string\",
  \"bodyFormat\": \"text\",
  \"replyAll\": false,
  \"sendViaEmail\": false
}"
```

## GET `/messages/object-types`

List registered message object types for a message type

**Tags:** Messages

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| messageType | query | any | Required |

### Responses

**200** – Message object types

Content-Type: `application/json`

```json
{
  "items": [
    {
      "module": "string",
      "entityType": "string",
      "labelKey": "string",
      "icon": "string",
      "actions": [
        {
          "id": "string",
          "labelKey": "string"
        }
      ]
    }
  ]
}
```

**400** – Invalid query

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/messages/object-types?messageType=string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/messages/token/{token}`

Access message via token

**Tags:** Messages

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| token | path | any | Required |

### Responses

**200** – Message detail via token

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "type": "string",
  "subject": "string",
  "body": "string",
  "bodyFormat": "text",
  "priority": "low",
  "senderUserId": "00000000-0000-4000-8000-000000000000",
  "sentAt": null,
  "actionData": null,
  "actionTaken": null,
  "actionTakenAt": null,
  "actionTakenByUserId": null,
  "objects": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "entityModule": "string",
      "entityType": "string",
      "entityId": "00000000-0000-4000-8000-000000000000",
      "actionRequired": true,
      "actionType": null,
      "actionLabel": null,
      "snapshot": null
    }
  ],
  "requiresAuth": true,
  "recipientUserId": "00000000-0000-4000-8000-000000000000"
}
```

**404** – Invalid or expired link

Content-Type: `application/json`

**409** – Token usage exceeded

Content-Type: `application/json`

**410** – Token expired

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/messages/token/:token" \
  -H "Accept: application/json"
```

## GET `/messages/types`

List registered message types

**Tags:** Messages

**Requires authentication.**

### Responses

**200** – Message types

Content-Type: `application/json`

```json
{
  "items": [
    {
      "type": "string",
      "module": "string",
      "labelKey": "string",
      "icon": "string",
      "color": null,
      "allowReply": true,
      "allowForward": true,
      "actionsExpireAfterHours": null,
      "ui": null
    }
  ]
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/messages/types" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/messages/unread-count`

Get unread message count

**Tags:** Messages

**Requires authentication.**

### Responses

**200** – Unread count

Content-Type: `application/json`

```json
{
  "unreadCount": 1
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/messages/unread-count" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/notifications`

List notifications

Returns a paginated collection of notifications.

**Tags:** Notifications

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| status | query | any | Optional |
| type | query | any | Optional |
| severity | query | any | Optional |
| sourceEntityType | query | any | Optional |
| sourceEntityId | query | any | Optional |
| since | query | any | Optional |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated notifications

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "type": "string",
      "title": "string",
      "body": null,
      "titleKey": null,
      "bodyKey": null,
      "titleVariables": null,
      "bodyVariables": null,
      "icon": null,
      "severity": "string",
      "status": "string",
      "actions": [
        {
          "id": "string",
          "label": "string"
        }
      ],
      "sourceModule": null,
      "sourceEntityType": null,
      "sourceEntityId": null,
      "linkHref": null,
      "createdAt": "string",
      "readAt": null,
      "actionTaken": null
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

**403** – Request could not be resolved to a tenant scope (code: tenant_scope_required)

Content-Type: `application/json`

```json
{
  "error": "string",
  "code": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/notifications?page=1&pageSize=20" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/notifications`

Create notification

Creates a notification for a user.

**Tags:** Notifications

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "type": "string",
  "severity": "info",
  "recipientUserId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**201** – Notification created

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/notifications" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"type\": \"string\",
  \"severity\": \"info\",
  \"recipientUserId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## POST `/notifications/{id}/action`

POST /notifications/{id}/action

**Tags:** Notifications

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/notifications/:id/action" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/notifications/{id}/dismiss`

PUT /notifications/{id}/dismiss

**Tags:** Notifications

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/notifications/:id/dismiss" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/notifications/{id}/read`

PUT /notifications/{id}/read

**Tags:** Notifications

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/notifications/:id/read" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/notifications/{id}/restore`

PUT /notifications/{id}/restore

**Tags:** Notifications

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/notifications/:id/restore" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/notifications/admin/preferences`

GET /notifications/admin/preferences

**Tags:** Notifications

**Requires authentication.**

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/notifications/admin/preferences" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/notifications/admin/preferences`

PUT /notifications/admin/preferences

**Tags:** Notifications

**Requires authentication.**

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/notifications/admin/preferences" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/notifications/batch`

POST /notifications/batch

**Tags:** Notifications

**Requires authentication.**

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/notifications/batch" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/notifications/channels`

GET /notifications/channels

**Tags:** Notifications

**Requires authentication.**

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/notifications/channels" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/notifications/feature`

POST /notifications/feature

**Tags:** Notifications

**Requires authentication.**

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/notifications/feature" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/notifications/mark-all-read`

PUT /notifications/mark-all-read

**Tags:** Notifications

**Requires authentication.**

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/notifications/mark-all-read" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/notifications/preferences`

GET /notifications/preferences

**Tags:** Notifications

**Requires authentication.**

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/notifications/preferences" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/notifications/preferences`

PUT /notifications/preferences

**Tags:** Notifications

**Requires authentication.**

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/notifications/preferences" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/notifications/role`

POST /notifications/role

**Tags:** Notifications

**Requires authentication.**

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/notifications/role" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/notifications/settings`

GET /notifications/settings

**Tags:** Notifications

**Requires authentication.**

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/notifications/settings" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/notifications/settings`

POST /notifications/settings

**Tags:** Notifications

**Requires authentication.**

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/notifications/settings" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/notifications/types`

GET /notifications/types

**Tags:** Notifications

**Requires authentication.**

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/notifications/types" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PATCH `/notifications/types`

PATCH /notifications/types

**Tags:** Notifications

**Requires authentication.**

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PATCH "https://demo-carrier.closare.com/api/notifications/types" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/notifications/types/{id}/channels/{channel}`

DELETE /notifications/types/{id}/channels/{channel}

**Tags:** Notifications

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| channel | path | any | Required |

### Responses

**204** – Success

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/notifications/types/:id/channels/:channel" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/notifications/types/{id}/channels/{channel}`

PUT /notifications/types/{id}/channels/{channel}

**Tags:** Notifications

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| channel | path | any | Required |

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/notifications/types/:id/channels/:channel" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/notifications/unread-count`

GET /notifications/unread-count

**Tags:** Notifications

**Requires authentication.**

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/notifications/unread-count" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/perspectives/{tableId}`

Load perspectives for a table

Returns personal perspectives and available role defaults for the requested table identifier.

**Tags:** Perspectives

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| tableId | path | any | Required |

### Responses

**200** – Current perspectives and defaults.

Content-Type: `application/json`

```json
{
  "tableId": "string",
  "perspectives": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "tableId": "string",
      "settings": {},
      "isDefault": true,
      "createdAt": "string",
      "updatedAt": null
    }
  ],
  "defaultPerspectiveId": null,
  "rolePerspectives": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "tableId": "string",
      "settings": {},
      "isDefault": true,
      "createdAt": "string",
      "updatedAt": null,
      "roleId": "00000000-0000-4000-8000-000000000000",
      "tenantId": null,
      "organizationId": null,
      "roleName": null
    }
  ],
  "manageableRolePerspectives": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "tableId": "string",
      "settings": {},
      "isDefault": true,
      "createdAt": "string",
      "updatedAt": null,
      "roleId": "00000000-0000-4000-8000-000000000000",
      "tenantId": null,
      "organizationId": null,
      "roleName": null
    }
  ],
  "roles": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "hasPerspective": true,
      "hasDefault": true
    }
  ],
  "canApplyToRoles": true
}
```

**400** – Invalid table identifier

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/perspectives/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/perspectives/{tableId}`

Create or update a perspective

Saves a personal perspective and optionally applies the same configuration to selected roles.

**Tags:** Perspectives

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| tableId | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "name": "string",
  "settings": {}
}
```

### Responses

**200** – Perspective saved successfully.

Content-Type: `application/json`

```json
{
  "perspective": {
    "id": "00000000-0000-4000-8000-000000000000",
    "name": "string",
    "tableId": "string",
    "settings": {},
    "isDefault": true,
    "createdAt": "string",
    "updatedAt": null
  },
  "rolePerspectives": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "tableId": "string",
      "settings": {},
      "isDefault": true,
      "createdAt": "string",
      "updatedAt": null,
      "roleId": "00000000-0000-4000-8000-000000000000",
      "tenantId": null,
      "organizationId": null,
      "roleName": null
    }
  ],
  "clearedRoleIds": [
    "00000000-0000-4000-8000-000000000000"
  ]
}
```

**400** – Validation failed or invalid roles provided

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Missing perspectives.role_defaults feature for role updates

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**409** – Optimistic lock conflict or perspective name already exists

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/perspectives/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"name\": \"string\",
  \"settings\": {}
}"
```

## DELETE `/perspectives/{tableId}/{perspectiveId}`

Delete a personal perspective

Removes a perspective owned by the current user for the given table.

**Tags:** Perspectives

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| tableId | path | any | Required |
| perspectiveId | path | any | Required |

### Responses

**200** – Perspective removed.

Content-Type: `application/json`

```json
{
  "success": true
}
```

**400** – Invalid identifiers supplied

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Perspective not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**409** – Optimistic lock conflict

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/perspectives/string/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/perspectives/{tableId}/roles/{roleId}`

Clear role perspectives for a table

Removes all role-level perspectives associated with the provided role identifier for the table.

**Tags:** Perspectives

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| tableId | path | any | Required |
| roleId | path | any | Required |

### Request Body

Content-Type: `application/json`

No example available for this content type.

### Responses

**200** – Role perspectives cleared.

Content-Type: `application/json`

```json
{
  "success": true
}
```

**400** – Invalid identifiers supplied

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Missing perspectives.role_defaults feature

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Role not found in scope

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**409** – Optimistic lock conflict

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/perspectives/string/roles/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/query_index/purge`

Purge query index records

Queues a purge job to remove indexed records for an entity type within the active scope.

**Tags:** Query Index

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "entityType": "string"
}
```

### Responses

**200** – Purge job accepted.

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Missing entity type

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/query_index/purge" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityType\": \"string\"
}"
```

## POST `/query_index/reindex`

Trigger query index rebuild

Queues a reindex job for the specified entity type within the current tenant scope.

**Tags:** Query Index

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "entityType": "string"
}
```

### Responses

**200** – Reindex job accepted.

Content-Type: `application/json`

```json
{
  "ok": true
}
```

**400** – Missing entity type

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/query_index/reindex" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityType\": \"string\"
}"
```

## GET `/query_index/status`

Inspect query index coverage

Returns entity counts comparing base tables with the query index along with the latest job status.

**Tags:** Query Index

**Requires authentication.**

### Responses

**200** – Current query index status.

Content-Type: `application/json`

```json
{
  "items": [
    {
      "entityId": "string",
      "label": "string",
      "baseCount": null,
      "indexCount": null,
      "vectorCount": null,
      "fulltextCount": null,
      "ok": true,
      "job": {
        "status": "idle",
        "startedAt": null,
        "finishedAt": null,
        "heartbeatAt": null,
        "processedCount": null,
        "totalCount": null,
        "scope": null
      },
      "refreshedAt": null
    }
  ],
  "errors": [
    {
      "id": "string",
      "source": "string",
      "handler": "string",
      "entityType": null,
      "recordId": null,
      "tenantId": null,
      "organizationId": null,
      "message": "string",
      "stack": null,
      "payload": null,
      "occurredAt": "string"
    }
  ],
  "logs": [
    {
      "id": "string",
      "source": "string",
      "handler": "string",
      "level": "info",
      "entityType": null,
      "recordId": null,
      "tenantId": null,
      "organizationId": null,
      "message": "string",
      "details": null,
      "occurredAt": "string"
    }
  ]
}
```

**400** – Tenant or organization context required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Authentication required

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/query_index/status" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/scheduler/jobs`

Delete scheduledjob

Deletes a scheduled job by ID.

**Tags:** Scheduler

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "string"
}
```

### Responses

**200** – ScheduledJob deleted

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/scheduler/jobs" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"string\"
}"
```

## GET `/scheduler/jobs`

List scheduledjobs

Returns a paginated collection of scheduledjobs scoped to the authenticated organization.

**Tags:** Scheduler

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| id | query | any | Optional |
| search | query | any | Optional |
| scopeType | query | any | Optional |
| isEnabled | query | any | Required |
| sourceType | query | any | Optional |
| sourceModule | query | any | Optional |
| sort | query | any | Optional |
| order | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated scheduledjobs

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "description": null,
      "scopeType": "system",
      "organizationId": null,
      "tenantId": null,
      "scheduleType": "cron",
      "scheduleValue": "string",
      "timezone": "string",
      "targetType": "queue",
      "targetQueue": null,
      "targetCommand": null,
      "targetPayload": null,
      "requireFeature": null,
      "isEnabled": true,
      "lastRunAt": null,
      "nextRunAt": null,
      "sourceType": "user",
      "sourceModule": null,
      "createdAt": "string",
      "updatedAt": "string"
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/scheduler/jobs?page=1&pageSize=20" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/scheduler/jobs`

Create scheduledjob

Creates a new scheduled job with cron or interval-based scheduling.

**Tags:** Scheduler

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "name": "string",
  "description": null,
  "scopeType": "system",
  "organizationId": null,
  "tenantId": null,
  "scheduleType": "cron",
  "scheduleValue": "string",
  "timezone": "UTC",
  "targetType": "queue",
  "targetQueue": null,
  "targetCommand": null,
  "targetPayload": null,
  "requireFeature": null,
  "isEnabled": true,
  "sourceType": "user",
  "sourceModule": null
}
```

### Responses

**201** – ScheduledJob created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/scheduler/jobs" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"name\": \"string\",
  \"description\": null,
  \"scopeType\": \"system\",
  \"organizationId\": null,
  \"tenantId\": null,
  \"scheduleType\": \"cron\",
  \"scheduleValue\": \"string\",
  \"timezone\": \"UTC\",
  \"targetType\": \"queue\",
  \"targetQueue\": null,
  \"targetCommand\": null,
  \"targetPayload\": null,
  \"requireFeature\": null,
  \"isEnabled\": true,
  \"sourceType\": \"user\",
  \"sourceModule\": null
}"
```

## PUT `/scheduler/jobs`

Update scheduledjob

Updates an existing scheduled job by ID.

**Tags:** Scheduler

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "string",
  "description": null,
  "targetQueue": null,
  "targetCommand": null,
  "targetPayload": null,
  "requireFeature": null
}
```

### Responses

**200** – ScheduledJob updated

Content-Type: `application/json`

```json
{
  "ok": true
}
```

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/scheduler/jobs" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"string\",
  \"description\": null,
  \"targetQueue\": null,
  \"targetCommand\": null,
  \"targetPayload\": null,
  \"requireFeature\": null
}"
```

## GET `/scheduler/jobs/{id}/executions`

Get execution history for a schedule

Fetch recent executions from BullMQ for a scheduled job. Requires QUEUE_STRATEGY=async.

**Tags:** Scheduler

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| pageSize | query | any | Optional |

### Responses

**200** – Execution history

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "scheduleId": "00000000-0000-4000-8000-000000000000",
      "startedAt": "string",
      "finishedAt": null,
      "status": "running",
      "triggerType": "scheduled",
      "triggeredByUserId": null,
      "errorMessage": null,
      "errorStack": null,
      "durationMs": null,
      "queueJobId": "string",
      "queueName": "string",
      "attemptsMade": 1,
      "result": null
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1
}
```

**400** – Local strategy not supported

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Access denied

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Schedule not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/scheduler/jobs/:id/executions?pageSize=20" \
  -H "Accept: application/json"
```

## GET `/scheduler/queue-jobs/{jobId}`

Get BullMQ job details and logs

Fetch detailed information and logs for a queue job. Requires QUEUE_STRATEGY=async.

**Tags:** Scheduler

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| jobId | path | any | Required |
| queue | query | any | Required |

### Responses

**200** – Job details and logs

Content-Type: `application/json`

```json
{
  "id": "string",
  "name": "string",
  "state": "waiting",
  "progress": null,
  "returnvalue": null,
  "failedReason": null,
  "stacktrace": null,
  "attemptsMade": 1,
  "processedOn": null,
  "finishedOn": null,
  "logs": [
    "string"
  ]
}
```

**400** – Invalid request or local strategy not supported

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Access denied

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Job not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**500** – Internal server error

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/scheduler/queue-jobs/:jobId?queue=string" \
  -H "Accept: application/json"
```

## GET `/scheduler/targets`

List available queues and commands

Returns all registered queue names (from module workers) and explicitly scheduler-safe command IDs that can be used as schedule targets.

**Tags:** Scheduler

### Responses

**200** – Available targets

Content-Type: `application/json`

```json
{
  "queues": [
    {
      "value": "string",
      "label": "string"
    }
  ],
  "commands": [
    {
      "value": "string",
      "label": "string"
    }
  ]
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/scheduler/targets" \
  -H "Accept: application/json"
```

## POST `/scheduler/trigger`

Manually trigger a schedule

Executes a scheduled job immediately, bypassing the scheduled time. Only works with async queue strategy.

**Tags:** Scheduler

### Request Body

Content-Type: `application/json`

```json
{
  "id": "string"
}
```

### Responses

**200** – Schedule triggered successfully

Content-Type: `application/json`

```json
{
  "ok": true,
  "jobId": "string",
  "message": "string"
}
```

**400** – Invalid request or local strategy not supported

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**401** – Unauthorized

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**403** – Access denied

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

**404** – Schedule not found

Content-Type: `application/json`

```json
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/scheduler/trigger" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"string\"
}"
```

## DELETE `/storage-providers/s3/delete`

Delete file from S3

**Tags:** S3-Compatible Storage

### Responses

**204** – Success

### Example

```bash
curl -X DELETE "https://demo-carrier.closare.com/api/storage-providers/s3/delete" \
  -H "Accept: application/json"
```

## GET `/storage-providers/s3/download`

Download file from S3

**Tags:** S3-Compatible Storage

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/storage-providers/s3/download" \
  -H "Accept: application/json"
```

## GET `/storage-providers/s3/list`

List S3 objects

**Tags:** S3-Compatible Storage

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/storage-providers/s3/list" \
  -H "Accept: application/json"
```

## PUT `/storage-providers/s3/signed-upload/:token`

Upload through a bounded one-time compatibility URL

**Tags:** S3-Compatible Storage

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://demo-carrier.closare.com/api/storage-providers/s3/signed-upload/:token" \
  -H "Accept: application/json"
```

## POST `/storage-providers/s3/signed-url`

Generate S3 pre-signed URL

**Tags:** S3-Compatible Storage

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/storage-providers/s3/signed-url" \
  -H "Accept: application/json"
```

## POST `/storage-providers/s3/upload`

Upload file to S3

**Tags:** S3-Compatible Storage

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/storage-providers/s3/upload" \
  -H "Accept: application/json"
```

## GET `/tenant_closare_freight/sync`

Read the transport-order source configuration

**Tags:** Closare Freight

**Requires authentication.**

### Responses

**200** – The scoped configuration

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://demo-carrier.closare.com/api/tenant_closare_freight/sync" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/tenant_closare_freight/sync`

Configure the organization transport-order source

**Tags:** Closare Freight

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "requestId": "string",
  "provider": "freight-tms",
  "enabled": false
}
```

### Responses

**201** – Created configuration, disabled by default

Content-Type: `application/json`

**409** – Missing native connection or duplicate provider

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/tenant_closare_freight/sync" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"requestId\": \"string\",
  \"provider\": \"freight-tms\",
  \"enabled\": false
}"
```

## PATCH `/tenant_closare_freight/sync/{id}`

Enable or disable the transport-order source; history is retained

**Tags:** Closare Freight

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "requestId": "string",
  "updatedAt": "string",
  "enabled": true
}
```

### Responses

**200** – Versioned configuration result

Content-Type: `application/json`

**409** – Stale configuration or unavailable connection

Content-Type: `application/json`

### Example

```bash
curl -X PATCH "https://demo-carrier.closare.com/api/tenant_closare_freight/sync/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"requestId\": \"string\",
  \"updatedAt\": \"string\",
  \"enabled\": true
}"
```

## POST `/tenant_closare_freight/sync/{id}/run`

Request refresh of the enabled transport-order source

**Tags:** Closare Freight

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |

### Request Body

Content-Type: `application/json`

```json
{
  "requestId": "string",
  "updatedAt": "string"
}
```

### Responses

**200** – Durable request recorded; native sweep queued

Content-Type: `application/json`

**409** – Disabled source or stale version

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://demo-carrier.closare.com/api/tenant_closare_freight/sync/:id/run" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"requestId\": \"string\",
  \"updatedAt\": \"string\"
}"
```