# MyOMERP API

Version: 0.4.9

Auto-generated OpenAPI definition for all enabled modules.

## Servers
- https://crmprod.erp.sobota.myopenmercato.com – Default environment

## POST `/ai_assistant/chat`

POST /ai_assistant/chat

Requires features: ai_assistant.view

**Tags:** AI Assistant

**Requires authentication.**

**Features:** ai_assistant.view

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/ai_assistant/chat" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/ai_assistant/health`

GET /ai_assistant/health

Requires features: ai_assistant.view

**Tags:** AI Assistant

**Requires authentication.**

**Features:** ai_assistant.view

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/ai_assistant/health" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/ai_assistant/route`

POST /ai_assistant/route

Requires features: ai_assistant.view

**Tags:** AI Assistant

**Requires authentication.**

**Features:** ai_assistant.view

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/ai_assistant/route" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/ai_assistant/session-key`

Generate session key

Generates a new session token that can be included in MCP tool calls via the _sessionToken parameter. The token inherits the calling user's roles and organization context.

Requires features: ai_assistant.view

**Tags:** AI Assistant

**Requires authentication.**

**Features:** ai_assistant.view

### Responses

**200** – Session key created successfully

Content-Type: `application/json`

```json
{
  "sessionToken": "string",
  "expiresAt": "string"
}
```

**500** – Failed to create session key

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/ai_assistant/session-key" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/ai_assistant/settings`

GET /ai_assistant/settings

Requires features: ai_assistant.view

**Tags:** AI Assistant

**Requires authentication.**

**Features:** ai_assistant.view

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/ai_assistant/settings" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/ai_assistant/tools`

GET /ai_assistant/tools

Requires features: ai_assistant.view

**Tags:** AI Assistant

**Requires authentication.**

**Features:** ai_assistant.view

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/ai_assistant/tools" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/ai_assistant/tools/execute`

POST /ai_assistant/tools/execute

Requires features: ai_assistant.view

**Tags:** AI Assistant

**Requires authentication.**

**Features:** ai_assistant.view

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/ai_assistant/tools/execute" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## 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.

Requires features: api_keys.delete

**Tags:** API Keys

**Requires authentication.**

**Features:** api_keys.delete

### 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"
}
```

**404** – Key not found within scope

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: api_keys.view

**Tags:** API Keys

**Requires authentication.**

**Features:** api_keys.view

### 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"
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: api_keys.create

**Tags:** API Keys

**Requires authentication.**

**Features:** api_keys.create

### 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"
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: attachments.manage

**Tags:** Attachments

**Requires authentication.**

**Features:** attachments.manage

### 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"
}
```

**404** – Attachment not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: attachments.view

**Tags:** Attachments

**Requires authentication.**

**Features:** attachments.view

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

### 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"
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: attachments.manage

**Tags:** Attachments

**Requires authentication.**

**Features:** attachments.manage

### 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"
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/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://crmprod.erp.sobota.myopenmercato.com/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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: attachments.view

**Tags:** Attachments

**Requires authentication.**

**Features:** attachments.view

### 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"
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: attachments.manage

**Tags:** Attachments

**Requires authentication.**

**Features:** attachments.manage

### 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"
}
```

**404** – Attachment not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: attachments.view

**Tags:** Attachments

**Requires authentication.**

**Features:** attachments.view

### 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"
}
```

**404** – Attachment not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: attachments.manage

**Tags:** Attachments

**Requires authentication.**

**Features:** attachments.manage

### 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"
}
```

**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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: attachments.manage

**Tags:** Attachments

**Requires authentication.**

**Features:** attachments.manage

### 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"
}
```

**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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: attachments.manage

**Tags:** Attachments

**Requires authentication.**

**Features:** attachments.manage

### 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,
      "createdAt": null,
      "updatedAt": null,
      "envKey": "string"
    }
  ]
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: attachments.manage

**Tags:** Attachments

**Requires authentication.**

**Features:** attachments.manage

### Request Body

Content-Type: `application/json`

```json
{
  "code": "string",
  "title": "string",
  "description": null,
  "ocrModel": 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,
    "createdAt": null,
    "updatedAt": null,
    "envKey": "string"
  }
}
```

**400** – Invalid payload or partition code

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://crmprod.erp.sobota.myopenmercato.com/attachments/partitions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"code\": \"string\",
  \"title\": \"string\",
  \"description\": null,
  \"ocrModel\": 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.

Requires features: attachments.manage

**Tags:** Attachments

**Requires authentication.**

**Features:** attachments.manage

### Request Body

Content-Type: `application/json`

```json
{
  "code": "string",
  "title": "string",
  "description": null,
  "ocrModel": 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,
    "createdAt": null,
    "updatedAt": null,
    "envKey": "string"
  }
}
```

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

Content-Type: `application/json`

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

**404** – Partition not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/attachments/partitions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"code\": \"string\",
  \"title\": \"string\",
  \"description\": null,
  \"ocrModel\": 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.

Requires features: attachments.manage

**Tags:** Attachments

**Requires authentication.**

**Features:** attachments.manage

### 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"
}
```

**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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: audit_logs.view_self

**Tags:** Audit & Action Logs

**Requires authentication.**

**Features:** audit_logs.view_self

### 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"
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: audit_logs.view_self

**Tags:** Audit & Action Logs

**Requires authentication.**

**Features:** audit_logs.view_self

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| organizationId | query | any | Optional. Limit results to a specific organization |
| actorUserId | query | any | Optional. Filter logs created by a specific actor (tenant administrators only) |
| 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) |
| 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 return (default 50) |
| 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
}
```

**400** – Invalid filter values

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/audit_logs/audit-logs/actions?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.

Requires features: audit_logs.redo_self

**Tags:** Audit & Action Logs

**Requires authentication.**

**Features:** audit_logs.redo_self

### 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"
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: audit_logs.undo_self

**Tags:** Audit & Action Logs

**Requires authentication.**

**Features:** audit_logs.undo_self

### 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"
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/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 sidebar entries

Returns the backend navigation tree available to the authenticated administrator after applying role and personal sidebar preferences.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Responses

**200** – Sidebar navigation structure

Content-Type: `application/json`

```json
{
  "groups": [
    {
      "id": "string",
      "name": "string",
      "defaultName": "string",
      "items": [
        {
          "href": "string",
          "title": "string",
          "defaultTitle": "string",
          "enabled": true
        }
      ]
    }
  ]
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/auth/admin/nav" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## 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"
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: auth.acl.manage

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.acl.manage

### Responses

**200** – Aggregated feature catalog

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/auth/features" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/auth/locale`

GET /auth/locale

**Tags:** Authentication & Accounts

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/auth/locale" \
  -H "Accept: application/json"
```

## POST `/auth/locale`

POST /auth/locale

**Tags:** Authentication & Accounts

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/auth/locale" \
  -H "Accept: application/json"
```

## 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://crmprod.erp.sobota.myopenmercato.com/auth/login" \
  -H "Accept: application/json" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "email=user%40example.com&password=string"
```

## GET `/auth/logout`

Log out (legacy GET)

For convenience, the GET variant performs the same logout logic as POST and issues a redirect.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Responses

**200** – Success response

Content-Type: `application/json`

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

Content-Type: `text/html`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/auth/logout" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## 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://crmprod.erp.sobota.myopenmercato.com/auth/logout" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/auth/profile`

Get current profile

Returns the email address for the signed-in user.

**Tags:** Authentication & Accounts

**Requires authentication.**

### Responses

**200** – Profile payload

Content-Type: `application/json`

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

**404** – User not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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"
}
```

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/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
}
```

**429** – Too many password reset requests

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: auth.roles.manage

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.roles.manage

### 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"
}
```

**404** – Role not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: auth.roles.list

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.roles.list

### 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
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/auth/roles?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/auth/roles`

Create role

Creates a new role for the current tenant or globally when `tenantId` is omitted.

Requires features: auth.roles.manage

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.roles.manage

### Request Body

Content-Type: `application/json`

```json
{
  "name": "string",
  "tenantId": null
}
```

### 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"
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/auth/roles" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"name\": \"string\",
  \"tenantId\": null
}"
```

## PUT `/auth/roles`

Update role

Updates mutable fields on an existing role.

Requires features: auth.roles.manage

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.roles.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Role updated

Content-Type: `application/json`

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

**400** – Invalid payload

Content-Type: `application/json`

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

**404** – Role not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/auth/roles" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": null
}"
```

## GET `/auth/roles/acl`

Fetch role ACL

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

Requires features: auth.acl.manage

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.acl.manage

### 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
}
```

**400** – Invalid role id

Content-Type: `application/json`

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

**404** – Role not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: auth.acl.manage

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.acl.manage

### 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"
}
```

**404** – Role not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/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://crmprod.erp.sobota.myopenmercato.com/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://crmprod.erp.sobota.myopenmercato.com/auth/session/refresh" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"refreshToken\": \"string\"
}"
```

## GET `/auth/sidebar/preferences`

Get sidebar preferences

Returns personal sidebar customization and any role-level preferences the user can 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"
    ]
  },
  "canApplyToRoles": true,
  "roles": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "hasPreference": true
    }
  ]
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/auth/sidebar/preferences" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/auth/sidebar/preferences`

Update sidebar preferences

Updates personal sidebar configuration and, optionally, applies the same settings to selected roles.

**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"
    ]
  },
  "canApplyToRoles": true,
  "roles": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "hasPreference": true
    }
  ],
  "appliedRoles": [
    "00000000-0000-4000-8000-000000000000"
  ],
  "clearedRoles": [
    "00000000-0000-4000-8000-000000000000"
  ]
}
```

**400** – Invalid payload

Content-Type: `application/json`

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

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

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/auth/sidebar/preferences" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## DELETE `/auth/users`

Delete user

Deletes a user by identifier. Undo support is provided via the command bus.

Requires features: auth.users.delete

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.users.delete

### 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

Content-Type: `application/json`

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

**404** – User not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/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 current tenant. Super administrators may scope the response via organization or role filters.

Requires features: auth.users.list

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.users.list

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | query | any | Optional |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| organizationId | 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",
      "organizationId": null,
      "organizationName": null,
      "tenantId": null,
      "tenantName": null,
      "roles": [
        "string"
      ]
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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 and optional roles.

Requires features: auth.users.create

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.users.create

### Request Body

Content-Type: `application/json`

```json
{
  "email": "user@example.com",
  "password": "string",
  "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"
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/auth/users" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"email\": \"user@example.com\",
  \"password\": \"string\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## PUT `/auth/users`

Update user

Updates profile fields, organization assignment, credentials, or role memberships.

Requires features: auth.users.edit

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.users.edit

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – User updated

Content-Type: `application/json`

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

**400** – Invalid payload

Content-Type: `application/json`

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

**404** – User not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/auth/users" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/auth/users/acl`

Fetch user ACL

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

Requires features: auth.acl.manage

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.acl.manage

### 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
}
```

**400** – Invalid user id

Content-Type: `application/json`

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

### Example

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

## PUT `/auth/users/acl`

Update user ACL

Configures per-user ACL overrides, including super admin access, feature list, and organization scope.

Requires features: auth.acl.manage

**Tags:** Authentication & Accounts

**Requires authentication.**

**Features:** auth.acl.manage

### 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"
}
```

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: auth.users.edit

**Tags:** Auth

**Requires authentication.**

**Features:** auth.users.edit

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

### Responses

**200** – Consent list returned

Content-Type: `application/json`

### Example

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

## POST `/business_rules/execute`

Execute rules for given context

Manually executes applicable business rules for the specified entity type, event, and data. Supports dry-run mode to test rules without executing actions.

Requires features: business_rules.execute

**Tags:** Business Rules

**Requires authentication.**

**Features:** business_rules.execute

### Request Body

Content-Type: `application/json`

```json
{
  "entityType": "string",
  "dryRun": false
}
```

### Responses

**200** – Rules executed successfully

Content-Type: `application/json`

```json
{
  "allowed": true,
  "executedRules": [
    {
      "ruleId": "string",
      "ruleName": "string",
      "conditionResult": true,
      "executionTime": 1
    }
  ],
  "totalExecutionTime": 1
}
```

**400** – Invalid request payload

Content-Type: `application/json`

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

**500** – Execution error

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/business_rules/execute" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityType\": \"string\",
  \"dryRun\": false
}"
```

## POST `/business_rules/execute/{ruleId}`

Execute a specific rule by its database UUID

Directly executes a specific business rule identified by its UUID, bypassing the normal entityType/eventType discovery mechanism. Useful for workflows and targeted rule execution.

Requires features: business_rules.execute

**Tags:** Business Rules

**Requires authentication.**

**Features:** business_rules.execute

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| ruleId | path | any | Required. The database UUID of the business rule to execute |

### Request Body

Content-Type: `application/json`

```json
{
  "dryRun": false
}
```

### Responses

**200** – Rule executed successfully

Content-Type: `application/json`

```json
{
  "success": true,
  "ruleId": "string",
  "ruleName": "string",
  "conditionResult": true,
  "actionsExecuted": null,
  "executionTime": 1
}
```

**400** – Invalid request payload or rule ID

Content-Type: `application/json`

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

**404** – Rule not found

Content-Type: `application/json`

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

**500** – Execution error

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/business_rules/execute/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"dryRun\": false
}"
```

## GET `/business_rules/logs`

List rule execution logs

Returns rule execution history for the current tenant and organization with filtering and pagination. Useful for audit trails and debugging.

Requires features: business_rules.view_logs

**Tags:** Business Rules

**Requires authentication.**

**Features:** business_rules.view_logs

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | query | any | Optional |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| ruleId | query | any | Optional |
| entityId | query | any | Optional |
| entityType | query | any | Optional |
| executionResult | query | any | Optional |
| executedBy | query | any | Optional |
| executedAtFrom | query | any | Optional |
| executedAtTo | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |

### Responses

**200** – Rule execution logs collection

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "ruleId": "string",
      "ruleName": "string",
      "ruleType": "string",
      "entityId": "00000000-0000-4000-8000-000000000000",
      "entityType": "string",
      "executionResult": "SUCCESS",
      "inputContext": null,
      "outputContext": null,
      "errorMessage": null,
      "executionTimeMs": 1,
      "executedAt": "string",
      "tenantId": "00000000-0000-4000-8000-000000000000",
      "organizationId": null,
      "executedBy": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

**400** – Invalid query parameters

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/business_rules/logs?page=1&pageSize=50&sortDir=desc" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/business_rules/logs/{id}`

Get execution log detail

Returns detailed information about a specific rule execution, including full context and results.

Requires features: business_rules.view_logs

**Tags:** Business Rules

**Requires authentication.**

**Features:** business_rules.view_logs

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

### Responses

**200** – Log entry details

Content-Type: `application/json`

```json
{
  "id": "string",
  "rule": {
    "id": "00000000-0000-4000-8000-000000000000",
    "ruleId": "string",
    "ruleName": "string",
    "ruleType": "string",
    "entityType": "string"
  },
  "entityId": "00000000-0000-4000-8000-000000000000",
  "entityType": "string",
  "executionResult": "SUCCESS",
  "inputContext": null,
  "outputContext": null,
  "errorMessage": null,
  "executionTimeMs": 1,
  "executedAt": "string",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": null,
  "executedBy": null
}
```

**400** – Invalid log id

Content-Type: `application/json`

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

**404** – Log entry not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/business_rules/logs/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/business_rules/rules`

Delete business rule

Soft deletes a business rule by identifier.

Requires features: business_rules.manage

**Tags:** Business Rules

**Requires authentication.**

**Features:** business_rules.manage

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

### Responses

**200** – Business rule deleted

Content-Type: `application/json`

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

**400** – Invalid identifier

Content-Type: `application/json`

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

**404** – Business rule not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/business_rules/rules?id=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/business_rules/rules`

List business rules

Returns business rules for the current tenant and organization with filtering and pagination.

Requires features: business_rules.view

**Tags:** Business Rules

**Requires authentication.**

**Features:** business_rules.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | query | any | Optional |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| ruleId | query | any | Optional |
| ruleType | query | any | Optional |
| entityType | query | any | Optional |
| eventType | query | any | Optional |
| enabled | query | any | Optional |
| ruleCategory | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |

### Responses

**200** – Business rules collection

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "ruleId": "string",
      "ruleName": "string",
      "description": null,
      "ruleType": "GUARD",
      "ruleCategory": null,
      "entityType": "string",
      "eventType": null,
      "enabled": true,
      "priority": 1,
      "version": 1,
      "effectiveFrom": null,
      "effectiveTo": null,
      "tenantId": "00000000-0000-4000-8000-000000000000",
      "organizationId": "00000000-0000-4000-8000-000000000000",
      "createdAt": "string",
      "updatedAt": "string"
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

**400** – Invalid query parameters

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/business_rules/rules?page=1&pageSize=50&sortDir=desc" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/business_rules/rules`

Create business rule

Creates a new business rule for the current tenant and organization.

Requires features: business_rules.manage

**Tags:** Business Rules

**Requires authentication.**

**Features:** business_rules.manage

### Request Body

Content-Type: `application/json`

```json
{
  "ruleId": "string",
  "ruleName": "string",
  "description": null,
  "ruleType": "GUARD",
  "ruleCategory": null,
  "entityType": "string",
  "eventType": null,
  "enabled": true,
  "priority": 100,
  "version": 1,
  "effectiveFrom": null,
  "effectiveTo": null,
  "tenantId": "string",
  "organizationId": "string",
  "createdBy": null,
  "successActions": null,
  "failureActions": null
}
```

### Responses

**201** – Business rule created

Content-Type: `application/json`

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

**400** – Invalid payload

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/business_rules/rules" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"ruleId\": \"string\",
  \"ruleName\": \"string\",
  \"description\": null,
  \"ruleType\": \"GUARD\",
  \"ruleCategory\": null,
  \"entityType\": \"string\",
  \"eventType\": null,
  \"enabled\": true,
  \"priority\": 100,
  \"version\": 1,
  \"effectiveFrom\": null,
  \"effectiveTo\": null,
  \"tenantId\": \"string\",
  \"organizationId\": \"string\",
  \"createdBy\": null,
  \"successActions\": null,
  \"failureActions\": null
}"
```

## PUT `/business_rules/rules`

Update business rule

Updates an existing business rule.

Requires features: business_rules.manage

**Tags:** Business Rules

**Requires authentication.**

**Features:** business_rules.manage

### Request Body

Content-Type: `application/json`

```json
{
  "description": null,
  "ruleCategory": null,
  "eventType": null,
  "enabled": true,
  "priority": 100,
  "version": 1,
  "effectiveFrom": null,
  "effectiveTo": null,
  "createdBy": null,
  "successActions": null,
  "failureActions": null,
  "id": "string"
}
```

### Responses

**200** – Business rule updated

Content-Type: `application/json`

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

**400** – Invalid payload

Content-Type: `application/json`

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

**404** – Business rule not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/business_rules/rules" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"description\": null,
  \"ruleCategory\": null,
  \"eventType\": null,
  \"enabled\": true,
  \"priority\": 100,
  \"version\": 1,
  \"effectiveFrom\": null,
  \"effectiveTo\": null,
  \"createdBy\": null,
  \"successActions\": null,
  \"failureActions\": null,
  \"id\": \"string\"
}"
```

## GET `/business_rules/rules/{id}`

Fetch business rule by ID

Returns complete details of a business rule including conditions and actions.

Requires features: business_rules.view

**Tags:** Business Rules

**Requires authentication.**

**Features:** business_rules.view

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

### Responses

**200** – Business rule detail

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "ruleId": "string",
  "ruleName": "string",
  "description": null,
  "ruleType": "GUARD",
  "ruleCategory": null,
  "entityType": "string",
  "eventType": null,
  "successActions": null,
  "failureActions": null,
  "enabled": true,
  "priority": 1,
  "version": 1,
  "effectiveFrom": null,
  "effectiveTo": null,
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "createdBy": null,
  "updatedBy": null,
  "createdAt": "string",
  "updatedAt": "string"
}
```

**400** – Invalid identifier

Content-Type: `application/json`

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

**404** – Business rule not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/business_rules/rules/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/business_rules/sets`

Delete rule set

Soft deletes a rule set by identifier.

Requires features: business_rules.manage_sets

**Tags:** Business Rules

**Requires authentication.**

**Features:** business_rules.manage_sets

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

### Responses

**200** – Rule set deleted

Content-Type: `application/json`

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

**400** – Invalid identifier

Content-Type: `application/json`

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

**404** – Rule set not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/business_rules/sets?id=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/business_rules/sets`

List rule sets

Returns rule sets for the current tenant and organization with filtering and pagination.

Requires features: business_rules.view

**Tags:** Business Rules

**Requires authentication.**

**Features:** business_rules.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | query | any | Optional |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| setId | query | any | Optional |
| enabled | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |

### Responses

**200** – Rule sets collection

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "setId": "string",
      "setName": "string",
      "description": null,
      "enabled": true,
      "tenantId": "00000000-0000-4000-8000-000000000000",
      "organizationId": "00000000-0000-4000-8000-000000000000",
      "createdBy": null,
      "updatedBy": null,
      "createdAt": "string",
      "updatedAt": "string"
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

**400** – Invalid query parameters

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/business_rules/sets?page=1&pageSize=50&sortDir=asc" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/business_rules/sets`

Create rule set

Creates a new rule set for organizing business rules.

Requires features: business_rules.manage_sets

**Tags:** Business Rules

**Requires authentication.**

**Features:** business_rules.manage_sets

### Request Body

Content-Type: `application/json`

```json
{
  "setId": "string",
  "setName": "string",
  "description": null,
  "enabled": true,
  "tenantId": "string",
  "organizationId": "string",
  "createdBy": null
}
```

### Responses

**201** – Rule set created

Content-Type: `application/json`

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

**400** – Invalid payload

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/business_rules/sets" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"setId\": \"string\",
  \"setName\": \"string\",
  \"description\": null,
  \"enabled\": true,
  \"tenantId\": \"string\",
  \"organizationId\": \"string\",
  \"createdBy\": null
}"
```

## PUT `/business_rules/sets`

Update rule set

Updates an existing rule set.

Requires features: business_rules.manage_sets

**Tags:** Business Rules

**Requires authentication.**

**Features:** business_rules.manage_sets

### Request Body

Content-Type: `application/json`

```json
{
  "description": null,
  "enabled": true,
  "createdBy": null,
  "id": "string"
}
```

### Responses

**200** – Rule set updated

Content-Type: `application/json`

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

**400** – Invalid payload

Content-Type: `application/json`

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

**404** – Rule set not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/business_rules/sets" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"description\": null,
  \"enabled\": true,
  \"createdBy\": null,
  \"id\": \"string\"
}"
```

## GET `/business_rules/sets/{id}`

Get rule set detail

Returns detailed information about a specific rule set, including all member rules.

Requires features: business_rules.view

**Tags:** Business Rules

**Requires authentication.**

**Features:** business_rules.view

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

### Responses

**200** – Rule set details

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "setId": "string",
  "setName": "string",
  "description": null,
  "enabled": true,
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "createdBy": null,
  "updatedBy": null,
  "createdAt": "string",
  "updatedAt": "string",
  "members": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "ruleId": "00000000-0000-4000-8000-000000000000",
      "ruleName": "string",
      "ruleType": "string",
      "sequence": 1,
      "enabled": true
    }
  ]
}
```

**400** – Invalid rule set id

Content-Type: `application/json`

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

**404** – Rule set not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/business_rules/sets/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/business_rules/sets/{id}/members`

Remove rule from set

Removes a business rule from a rule set (hard delete).

Requires features: business_rules.manage_sets

**Tags:** Business Rules

**Requires authentication.**

**Features:** business_rules.manage_sets

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| memberId | query | any | Required. Member identifier |

### Responses

**200** – Member removed

Content-Type: `application/json`

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

**400** – Invalid identifier

Content-Type: `application/json`

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

**404** – Member not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/business_rules/sets/:id/members?memberId=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/business_rules/sets/{id}/members`

Add rule to set

Adds a business rule to a rule set with specified sequence and enabled state.

Requires features: business_rules.manage_sets

**Tags:** Business Rules

**Requires authentication.**

**Features:** business_rules.manage_sets

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

### Request Body

Content-Type: `application/json`

```json
{
  "ruleId": "00000000-0000-4000-8000-000000000000",
  "sequence": 0,
  "enabled": true
}
```

### Responses

**201** – Member added

Content-Type: `application/json`

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

**400** – Invalid payload

Content-Type: `application/json`

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

**404** – Rule set or rule not found

Content-Type: `application/json`

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

**409** – Rule already in set

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/business_rules/sets/:id/members" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"ruleId\": \"00000000-0000-4000-8000-000000000000\",
  \"sequence\": 0,
  \"enabled\": true
}"
```

## PUT `/business_rules/sets/{id}/members`

Update set member

Updates sequence or enabled state of a rule set member.

Requires features: business_rules.manage_sets

**Tags:** Business Rules

**Requires authentication.**

**Features:** business_rules.manage_sets

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

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Member updated

Content-Type: `application/json`

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

**400** – Invalid payload

Content-Type: `application/json`

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

**404** – Member not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/business_rules/sets/:id/members" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"memberId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## POST `/catalog/bulk-delete`

Start bulk deleting catalog products

Requires features: catalog.products.manage

**Tags:** Product Catalog

**Requires authentication.**

**Features:** catalog.products.manage

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/catalog/bulk-delete" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/catalog/categories`

Delete category

Deletes a category by id.

Requires features: catalog.categories.manage

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.categories.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Category deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/catalog/categories" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/catalog/categories`

List categories

Returns a paginated collection of categories scoped to the authenticated organization.

Requires features: catalog.categories.view

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.categories.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| view | query | any | Optional |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| status | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated categories

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "slug": null,
      "description": null,
      "parentId": null,
      "parentName": null,
      "depth": 1,
      "treePath": "string",
      "pathLabel": "string",
      "childCount": 1,
      "descendantCount": 1,
      "isActive": true,
      "organizationId": "00000000-0000-4000-8000-000000000000",
      "tenantId": "00000000-0000-4000-8000-000000000000"
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/catalog/categories?view=manage&page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/catalog/categories`

Create category

Creates a new product category.

Requires features: catalog.categories.manage

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.categories.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "name": "string",
  "slug": null,
  "parentId": null
}
```

### Responses

**201** – Category created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/catalog/categories" \
  -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\",
  \"slug\": null,
  \"parentId\": null
}"
```

## PUT `/catalog/categories`

Update category

Updates an existing category by id.

Requires features: catalog.categories.manage

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.categories.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Category updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/catalog/categories" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"slug\": null,
  \"parentId\": null
}"
```

## GET `/catalog/dictionaries/{key}`

Get dictionary entries by key

Returns dictionary entries for a specific key (e.g., currency, unit).

Requires features: catalog.products.manage

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.products.manage

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

### Responses

**200** – Dictionary entries

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "entries": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "value": "string",
      "label": "string",
      "color": null,
      "icon": null
    }
  ]
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/catalog/dictionaries/:key" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/catalog/offers`

Delete offer

Deletes an offer by id.

Requires features: sales.channels.manage

**Tags:** Catalog

**Requires authentication.**

**Features:** sales.channels.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Offer deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/catalog/offers" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/catalog/offers`

List offers

Returns a paginated collection of offers scoped to the authenticated organization.

Requires features: sales.channels.manage

**Tags:** Catalog

**Requires authentication.**

**Features:** sales.channels.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| productId | query | any | Optional |
| channelId | query | any | Optional |
| channelIds | query | any | Optional |
| id | query | any | Optional |
| search | query | any | Optional |
| isActive | query | any | Optional |
| withDeleted | 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 offers

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "productId": null,
      "organizationId": null,
      "tenantId": null,
      "channelId": null,
      "title": "string",
      "description": null,
      "defaultMediaId": null,
      "defaultMediaUrl": null,
      "metadata": null,
      "isActive": null,
      "createdAt": null,
      "updatedAt": null,
      "product": null,
      "productChannelPrice": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/catalog/offers?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/catalog/offers`

Create offer

Creates a new offer linking a product to a sales channel.

Requires features: sales.channels.manage

**Tags:** Catalog

**Requires authentication.**

**Features:** sales.channels.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "channelId": "00000000-0000-4000-8000-000000000000",
  "title": "string",
  "defaultMediaId": null,
  "defaultMediaUrl": null,
  "productId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**201** – Offer created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/catalog/offers" \
  -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\",
  \"channelId\": \"00000000-0000-4000-8000-000000000000\",
  \"title\": \"string\",
  \"defaultMediaId\": null,
  \"defaultMediaUrl\": null,
  \"productId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## PUT `/catalog/offers`

Update offer

Updates an existing offer by id.

Requires features: sales.channels.manage

**Tags:** Catalog

**Requires authentication.**

**Features:** sales.channels.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Offer updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/catalog/offers" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"defaultMediaId\": null,
  \"defaultMediaUrl\": null
}"
```

## DELETE `/catalog/option-schemas`

Delete option schema

Deletes an option schema by id.

Requires features: catalog.settings.manage

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.settings.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Option Schema deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/catalog/option-schemas" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/catalog/option-schemas`

List option schemas

Returns a paginated collection of option schemas scoped to the authenticated organization.

Requires features: catalog.products.view

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.products.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| id | query | any | Optional |
| search | query | any | Optional |
| isActive | query | any | Optional |
| withDeleted | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated option schemas

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "code": null,
      "description": null,
      "schema": null,
      "metadata": null,
      "is_active": null,
      "created_at": null,
      "updated_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/catalog/option-schemas?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/catalog/option-schemas`

Create option schema

Creates a new option schema template for product configurations.

Requires features: catalog.settings.manage

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.settings.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "name": "string",
  "schema": {
    "options": [
      {
        "code": "string",
        "label": "string",
        "inputType": "select"
      }
    ]
  }
}
```

### Responses

**201** – Option Schema created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/catalog/option-schemas" \
  -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\",
  \"schema\": {
    \"options\": [
      {
        \"code\": \"string\",
        \"label\": \"string\",
        \"inputType\": \"select\"
      }
    ]
  }
}"
```

## PUT `/catalog/option-schemas`

Update option schema

Updates an existing option schema by id.

Requires features: catalog.settings.manage

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.settings.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Option Schema updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/catalog/option-schemas" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## DELETE `/catalog/price-kinds`

Delete price kind

Deletes a price kind by id.

Requires features: catalog.settings.manage

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.settings.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Price Kind deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/catalog/price-kinds" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/catalog/price-kinds`

List price kinds

Returns a paginated collection of price kinds scoped to the authenticated organization.

Requires features: catalog.settings.manage

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.settings.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| isPromotion | query | any | Optional |
| isActive | 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 price kinds

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "organization_id": null,
      "tenant_id": null,
      "code": "string",
      "title": "string",
      "display_mode": null,
      "currency_code": null,
      "is_promotion": null,
      "is_active": null,
      "created_at": null,
      "updated_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/catalog/price-kinds?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/catalog/price-kinds`

Create price kind

Creates a new price kind for categorizing product prices.

Requires features: catalog.settings.manage

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.settings.manage

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "code": "string",
  "title": "string",
  "displayMode": "excluding-tax"
}
```

### Responses

**201** – Price Kind created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/catalog/price-kinds" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"code\": \"string\",
  \"title\": \"string\",
  \"displayMode\": \"excluding-tax\"
}"
```

## PUT `/catalog/price-kinds`

Update price kind

Updates an existing price kind by id.

Requires features: catalog.settings.manage

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.settings.manage

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "displayMode": "excluding-tax"
}
```

### Responses

**200** – Price Kind updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/catalog/price-kinds" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"displayMode\": \"excluding-tax\"
}"
```

## DELETE `/catalog/prices`

Delete price

Deletes a price by id.

Requires features: catalog.pricing.manage

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.pricing.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Price deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/catalog/prices" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/catalog/prices`

List prices

Returns a paginated collection of prices scoped to the authenticated organization.

Requires features: catalog.products.view

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.products.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| productId | query | any | Optional |
| variantId | query | any | Optional |
| offerId | query | any | Optional |
| channelId | query | any | Optional |
| currencyCode | query | any | Optional |
| priceKindId | query | any | Optional |
| kind | query | any | Optional |
| userId | query | any | Optional |
| userGroupId | query | any | Optional |
| customerId | query | any | Optional |
| customerGroupId | query | any | Optional |
| quantity | query | any | Optional |
| quantityUnit | query | any | Optional |
| withDeleted | 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 prices

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "product_id": null,
      "variant_id": null,
      "offer_id": null,
      "currency_code": null,
      "price_kind_id": null,
      "kind": null,
      "min_quantity": null,
      "max_quantity": null,
      "unit_price_net": null,
      "unit_price_gross": null,
      "tax_rate": null,
      "tax_amount": null,
      "channel_id": null,
      "user_id": null,
      "user_group_id": null,
      "customer_id": null,
      "customer_group_id": null,
      "metadata": null,
      "starts_at": null,
      "ends_at": null,
      "created_at": null,
      "updated_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/catalog/prices?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/catalog/prices`

Create price

Creates a new price entry for a product or variant.

Requires features: catalog.pricing.manage

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.pricing.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "currencyCode": "string",
  "priceKindId": "00000000-0000-4000-8000-000000000000",
  "taxRateId": null
}
```

### Responses

**201** – Price created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/catalog/prices" \
  -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\",
  \"currencyCode\": \"string\",
  \"priceKindId\": \"00000000-0000-4000-8000-000000000000\",
  \"taxRateId\": null
}"
```

## PUT `/catalog/prices`

Update price

Updates an existing price by id.

Requires features: catalog.pricing.manage

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.pricing.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Price updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/catalog/prices" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"taxRateId\": null
}"
```

## GET `/catalog/product-media`

List product media

Returns a list of media attachments for a specific product.

Requires features: catalog.products.view

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.products.view

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

### Responses

**200** – List of product media

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "fileName": "string",
      "url": "string",
      "thumbnailUrl": "string"
    }
  ]
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/catalog/product-media?productId=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/catalog/product-unit-conversions`

Delete product unit conversion

Deletes a product unit conversion by id.

Requires features: catalog.products.manage

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.products.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Product unit conversion deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/catalog/product-unit-conversions" \
  -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\",
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/catalog/product-unit-conversions`

List product unit conversions

Returns a paginated collection of product unit conversions scoped to the authenticated organization.

Requires features: catalog.products.view

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.products.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| id | query | any | Optional |
| productId | query | any | Optional |
| unitCode | query | any | Optional |
| isActive | 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 product unit conversions

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "product_id": "00000000-0000-4000-8000-000000000000",
      "unit_code": "string",
      "to_base_factor": 1,
      "sort_order": null,
      "is_active": null,
      "metadata": null,
      "created_at": null,
      "updated_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/catalog/product-unit-conversions?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/catalog/product-unit-conversions`

Create product unit conversion

Creates a product unit conversion.

Requires features: catalog.products.manage

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.products.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "productId": "00000000-0000-4000-8000-000000000000",
  "unitCode": "string",
  "toBaseFactor": 1
}
```

### Responses

**201** – Product unit conversion created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/catalog/product-unit-conversions" \
  -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\",
  \"productId\": \"00000000-0000-4000-8000-000000000000\",
  \"unitCode\": \"string\",
  \"toBaseFactor\": 1
}"
```

## PUT `/catalog/product-unit-conversions`

Update product unit conversion

Updates an existing product unit conversion by id.

Requires features: catalog.products.manage

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.products.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Product unit conversion updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/catalog/product-unit-conversions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## DELETE `/catalog/products`

Delete product

Deletes a product by id.

Requires features: catalog.products.manage

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.products.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Product deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/catalog/products" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/catalog/products`

List products

Returns a paginated collection of products scoped to the authenticated organization.

Requires features: catalog.products.view

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.products.view

### 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 |
| isActive | query | any | Optional |
| configurable | query | any | Optional |
| productType | query | any | Optional |
| channelIds | query | any | Optional |
| channelId | query | any | Optional |
| categoryIds | query | any | Optional |
| tagIds | query | any | Optional |
| offerId | query | any | Optional |
| userId | query | any | Optional |
| userGroupId | query | any | Optional |
| customerId | query | any | Optional |
| customerGroupId | query | any | Optional |
| quantity | query | any | Optional |
| quantityUnit | query | any | Optional |
| priceDate | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| withDeleted | query | any | Optional |
| customFieldset | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated products

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "title": null,
      "subtitle": null,
      "description": null,
      "sku": null,
      "handle": null,
      "product_type": null,
      "status_entry_id": null,
      "primary_currency_code": null,
      "default_unit": null,
      "default_sales_unit": null,
      "default_sales_unit_quantity": null,
      "uom_rounding_scale": null,
      "uom_rounding_mode": null,
      "unit_price_enabled": null,
      "unit_price_reference_unit": null,
      "unit_price_base_quantity": null,
      "default_media_id": null,
      "default_media_url": null,
      "weight_value": null,
      "weight_unit": null,
      "dimensions": null,
      "is_configurable": null,
      "is_active": null,
      "metadata": null,
      "custom_fieldset_code": null,
      "option_schema_id": null,
      "created_at": null,
      "updated_at": null,
      "pricing": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/catalog/products?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/catalog/products`

Create product

Creates a new product in the catalog.

Requires features: catalog.products.manage

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.products.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "title": "string",
  "sku": null,
  "taxRateId": null,
  "taxRate": null,
  "productType": "simple",
  "defaultUnit": null,
  "defaultSalesUnit": null,
  "unitPriceReferenceUnit": null,
  "defaultMediaId": null,
  "defaultMediaUrl": null,
  "weightValue": null,
  "weightUnit": null,
  "dimensions": null,
  "optionSchemaId": null,
  "customFieldsetCode": null
}
```

### Responses

**201** – Product created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/catalog/products" \
  -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\",
  \"sku\": null,
  \"taxRateId\": null,
  \"taxRate\": null,
  \"productType\": \"simple\",
  \"defaultUnit\": null,
  \"defaultSalesUnit\": null,
  \"unitPriceReferenceUnit\": null,
  \"defaultMediaId\": null,
  \"defaultMediaUrl\": null,
  \"weightValue\": null,
  \"weightUnit\": null,
  \"dimensions\": null,
  \"optionSchemaId\": null,
  \"customFieldsetCode\": null
}"
```

## PUT `/catalog/products`

Update product

Updates an existing product by id.

Requires features: catalog.products.manage

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.products.manage

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "sku": null,
  "taxRateId": null,
  "taxRate": null,
  "defaultUnit": null,
  "defaultSalesUnit": null,
  "unitPriceReferenceUnit": null,
  "defaultMediaId": null,
  "defaultMediaUrl": null,
  "weightValue": null,
  "weightUnit": null,
  "dimensions": null,
  "optionSchemaId": null,
  "customFieldsetCode": null
}
```

### Responses

**200** – Product updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/catalog/products" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"sku\": null,
  \"taxRateId\": null,
  \"taxRate\": null,
  \"defaultUnit\": null,
  \"defaultSalesUnit\": null,
  \"unitPriceReferenceUnit\": null,
  \"defaultMediaId\": null,
  \"defaultMediaUrl\": null,
  \"weightValue\": null,
  \"weightUnit\": null,
  \"dimensions\": null,
  \"optionSchemaId\": null,
  \"customFieldsetCode\": null
}"
```

## GET `/catalog/tags`

List product tags

Returns a paginated collection of product tags scoped to the authenticated organization.

Requires features: catalog.products.view

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.products.view

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

### Responses

**200** – Paginated product tags

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "label": "string",
      "slug": null,
      "createdAt": "string",
      "updatedAt": "string"
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/catalog/tags?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/catalog/variants`

Delete variant

Deletes a variant by id.

Requires features: catalog.variants.manage

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.variants.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Variant deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/catalog/variants" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/catalog/variants`

List variants

Returns a paginated collection of variants scoped to the authenticated organization.

Requires features: catalog.products.view

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.products.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| id | query | any | Optional |
| search | query | any | Optional |
| productId | query | any | Optional |
| sku | query | any | Optional |
| isActive | query | any | Optional |
| isDefault | query | any | Optional |
| withDeleted | 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 variants

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "product_id": null,
      "name": null,
      "sku": null,
      "barcode": null,
      "status_entry_id": null,
      "is_default": null,
      "is_active": null,
      "weight_value": null,
      "weight_unit": null,
      "dimensions": null,
      "metadata": null,
      "option_values": null,
      "custom_fieldset_code": null,
      "created_at": null,
      "updated_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/catalog/variants?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/catalog/variants`

Create variant

Creates a new product variant.

Requires features: catalog.variants.manage

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.variants.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "productId": "00000000-0000-4000-8000-000000000000",
  "defaultMediaId": null,
  "defaultMediaUrl": null,
  "taxRateId": null,
  "taxRate": null,
  "customFieldsetCode": null
}
```

### Responses

**201** – Variant created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/catalog/variants" \
  -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\",
  \"productId\": \"00000000-0000-4000-8000-000000000000\",
  \"defaultMediaId\": null,
  \"defaultMediaUrl\": null,
  \"taxRateId\": null,
  \"taxRate\": null,
  \"customFieldsetCode\": null
}"
```

## PUT `/catalog/variants`

Update variant

Updates an existing variant by id.

Requires features: catalog.variants.manage

**Tags:** Catalog

**Requires authentication.**

**Features:** catalog.variants.manage

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "defaultMediaId": null,
  "defaultMediaUrl": null,
  "taxRateId": null,
  "taxRate": null,
  "customFieldsetCode": null
}
```

### Responses

**200** – Variant updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/catalog/variants" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"defaultMediaId\": null,
  \"defaultMediaUrl\": null,
  \"taxRateId\": null,
  \"taxRate\": null,
  \"customFieldsetCode\": null
}"
```

## GET `/checkout/links`

GET /checkout/links

Requires features: checkout.view

**Tags:** Checkout

**Requires authentication.**

**Features:** checkout.view

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/checkout/links" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/checkout/links`

POST /checkout/links

Requires features: checkout.create

**Tags:** Checkout

**Requires authentication.**

**Features:** checkout.create

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/checkout/links" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/checkout/links/{id}`

DELETE /checkout/links/{id}

Requires features: checkout.delete

**Tags:** Checkout

**Requires authentication.**

**Features:** checkout.delete

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

### Responses

**204** – Success

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/checkout/links/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/checkout/links/{id}`

GET /checkout/links/{id}

Requires features: checkout.view

**Tags:** Checkout

**Requires authentication.**

**Features:** checkout.view

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/checkout/links/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/checkout/links/{id}`

PUT /checkout/links/{id}

Requires features: checkout.edit

**Tags:** Checkout

**Requires authentication.**

**Features:** checkout.edit

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/checkout/links/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/checkout/pay/{slug}`

GET /checkout/pay/{slug}

**Tags:** Checkout

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/checkout/pay/:slug" \
  -H "Accept: application/json"
```

## GET `/checkout/pay/{slug}/status/{transactionId}`

GET /checkout/pay/{slug}/status/{transactionId}

**Tags:** Checkout

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/checkout/pay/:slug/status/:transactionId" \
  -H "Accept: application/json"
```

## POST `/checkout/pay/{slug}/submit`

POST /checkout/pay/{slug}/submit

**Tags:** Checkout

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

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/checkout/pay/:slug/submit" \
  -H "Accept: application/json"
```

## POST `/checkout/pay/{slug}/verify-password`

POST /checkout/pay/{slug}/verify-password

**Tags:** Checkout

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

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/checkout/pay/:slug/verify-password" \
  -H "Accept: application/json"
```

## GET `/checkout/templates`

GET /checkout/templates

Requires features: checkout.view

**Tags:** Checkout

**Requires authentication.**

**Features:** checkout.view

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/checkout/templates" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/checkout/templates`

POST /checkout/templates

Requires features: checkout.create

**Tags:** Checkout

**Requires authentication.**

**Features:** checkout.create

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/checkout/templates" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/checkout/templates/{id}`

DELETE /checkout/templates/{id}

Requires features: checkout.delete

**Tags:** Checkout

**Requires authentication.**

**Features:** checkout.delete

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

### Responses

**204** – Success

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/checkout/templates/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/checkout/templates/{id}`

GET /checkout/templates/{id}

Requires features: checkout.view

**Tags:** Checkout

**Requires authentication.**

**Features:** checkout.view

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/checkout/templates/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/checkout/templates/{id}`

PUT /checkout/templates/{id}

Requires features: checkout.edit

**Tags:** Checkout

**Requires authentication.**

**Features:** checkout.edit

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/checkout/templates/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/checkout/templates/{id}/preview`

GET /checkout/templates/{id}/preview

Requires features: checkout.view

**Tags:** Checkout

**Requires authentication.**

**Features:** checkout.view

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/checkout/templates/:id/preview" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/checkout/transactions`

GET /checkout/transactions

Requires features: checkout.view

**Tags:** Checkout

**Requires authentication.**

**Features:** checkout.view

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/checkout/transactions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/checkout/transactions/{id}`

GET /checkout/transactions/{id}

Requires features: checkout.view

**Tags:** Checkout

**Requires authentication.**

**Features:** checkout.view

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/checkout/transactions/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/checkout/transactions/by-gateway/{gatewayTransactionId}`

GET /checkout/transactions/by-gateway/{gatewayTransactionId}

Requires features: checkout.view

**Tags:** Checkout

**Requires authentication.**

**Features:** checkout.view

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/checkout/transactions/by-gateway/:gatewayTransactionId" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/configs/cache`

Get cache statistics

Returns detailed cache statistics including total entries and breakdown by cache segments. Requires cache service to be available.

Requires features: configs.cache.view

**Tags:** Configs

**Requires authentication.**

**Features:** configs.cache.view

### Responses

**200** – Cache statistics

Content-Type: `application/json`

```json
{
  "total": 1,
  "segments": {
    "key": 1
  }
}
```

**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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: configs.cache.manage

**Tags:** Configs

**Requires authentication.**

**Features:** configs.cache.manage

### 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": {
    "total": 1,
    "segments": {
      "key": 1
    }
  }
}
```

**400** – Invalid request - missing segment identifier for purgeSegment action

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://crmprod.erp.sobota.myopenmercato.com/configs/cache" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"action\": \"purgeAll\"
}"
```

## GET `/configs/system-status`

Get system health status

Returns comprehensive system health information including environment details, version, resource usage, and service connectivity status.

Requires features: configs.system_status.view

**Tags:** Configs

**Requires authentication.**

**Features:** configs.system_status.view

### 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
        }
      ]
    }
  ]
}
```

**500** – Failed to load system status

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: configs.manage

**Tags:** Configs

**Requires authentication.**

**Features:** configs.manage

### Responses

**200** – Cache cleared successfully

Content-Type: `application/json`

```json
{
  "cleared": true
}
```

**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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: configs.manage

**Tags:** Configs

**Requires authentication.**

**Features:** configs.manage

### 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"
}
```

**500** – Failed to load upgrade actions

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: configs.manage

**Tags:** Configs

**Requires authentication.**

**Features:** configs.manage

### 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"
}
```

**500** – Failed to execute upgrade action

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/configs/upgrade-actions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"actionId\": \"string\"
}"
```

## DELETE `/currencies/currencies`

Delete currency

Deletes a currency by id.

Requires features: currencies.manage

**Tags:** Currencies

**Requires authentication.**

**Features:** currencies.manage

### 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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: currencies.view

**Tags:** Currencies

**Requires authentication.**

**Features:** currencies.view

### 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://crmprod.erp.sobota.myopenmercato.com/currencies/currencies?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/currencies/currencies`

Create currency

Creates a new currency.

Requires features: currencies.manage

**Tags:** Currencies

**Requires authentication.**

**Features:** currencies.manage

### 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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: currencies.manage

**Tags:** Currencies

**Requires authentication.**

**Features:** currencies.manage

### 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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: currencies.view

**Tags:** Currencies

**Requires authentication.**

**Features:** currencies.view

### 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": []
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: currencies.rates.manage

**Tags:** Currencies

**Requires authentication.**

**Features:** currencies.rates.manage

### 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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: currencies.rates.view

**Tags:** Currencies

**Requires authentication.**

**Features:** currencies.rates.view

### 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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: currencies.rates.manage

**Tags:** Currencies

**Requires authentication.**

**Features:** currencies.rates.manage

### 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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: currencies.rates.manage

**Tags:** Currencies

**Requires authentication.**

**Features:** currencies.rates.manage

### 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://crmprod.erp.sobota.myopenmercato.com/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

### 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://crmprod.erp.sobota.myopenmercato.com/currencies/fetch-configs?id=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json"
```

## GET `/currencies/fetch-configs`

List currency fetch configurations

Returns all currency fetch configurations scoped to the authenticated organization.

**Tags:** Currencies

### 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://crmprod.erp.sobota.myopenmercato.com/currencies/fetch-configs" \
  -H "Accept: application/json"
```

## POST `/currencies/fetch-configs`

Create currency fetch configuration

Creates a new currency fetch configuration.

**Tags:** Currencies

### 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://crmprod.erp.sobota.myopenmercato.com/currencies/fetch-configs" \
  -H "Accept: application/json" \
  -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

### 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://crmprod.erp.sobota.myopenmercato.com/currencies/fetch-configs" \
  -H "Accept: application/json" \
  -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://crmprod.erp.sobota.myopenmercato.com/currencies/fetch-rates" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## GET `/customer_accounts/admin/roles`

List customer roles (admin)

Returns all customer roles for the tenant.

**Tags:** Customer Accounts Admin

### Responses

**200** – Role list

Content-Type: `application/json`

```json
{
  "ok": true,
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "slug": "string",
      "description": null,
      "isDefault": true,
      "isSystem": true,
      "customerAssignable": true,
      "createdAt": "string"
    }
  ],
  "total": 1,
  "totalPages": 1,
  "page": 1
}
```

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/admin/roles" \
  -H "Accept: application/json"
```

## POST `/customer_accounts/admin/roles`

Create customer role (admin)

Creates a new customer role with an empty ACL.

**Tags:** Customer Accounts Admin

### Request Body

Content-Type: `application/json`

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

### Responses

**201** – Role created

Content-Type: `application/json`

```json
{
  "ok": true,
  "role": {
    "id": "00000000-0000-4000-8000-000000000000",
    "name": "string",
    "slug": "string",
    "description": null,
    "isDefault": true,
    "isSystem": true,
    "customerAssignable": true,
    "createdAt": "string"
  }
}
```

**400** – Validation failed

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**409** – Slug already exists

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/admin/roles" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"name\": \"string\",
  \"slug\": \"string\"
}"
```

## DELETE `/customer_accounts/admin/roles/{id}`

Delete customer role (admin)

Soft deletes a customer role and its ACL. System roles and roles with assigned users cannot be deleted.

**Tags:** Customer Accounts Admin

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

### Responses

**200** – Role deleted

Content-Type: `application/json`

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

**400** – System role or has assigned users

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**404** – Role not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/admin/roles/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json"
```

## GET `/customer_accounts/admin/roles/{id}`

Get customer role detail (admin)

Returns full customer role details including ACL features.

**Tags:** Customer Accounts Admin

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

### Responses

**200** – Role detail with ACL

Content-Type: `application/json`

```json
{
  "ok": true,
  "role": {
    "id": "00000000-0000-4000-8000-000000000000",
    "name": "string",
    "slug": "string",
    "description": null,
    "isDefault": true,
    "isSystem": true,
    "customerAssignable": true,
    "createdAt": "string",
    "updatedAt": null,
    "acl": {
      "features": [
        "string"
      ],
      "isPortalAdmin": true
    }
  }
}
```

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**404** – Role not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/admin/roles/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json"
```

## PUT `/customer_accounts/admin/roles/{id}`

Update customer role (admin)

Updates a customer role. System roles are protected from name changes.

**Tags:** Customer Accounts Admin

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

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Role updated

Content-Type: `application/json`

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

**400** – Validation failed or system role restriction

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**404** – Role not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/admin/roles/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## PUT `/customer_accounts/admin/roles/{id}/acl`

Update customer role ACL (admin)

Updates the ACL (features and portal admin flag) for a customer role. Invalidates RBAC cache after update.

**Tags:** Customer Accounts Admin

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

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – ACL updated

Content-Type: `application/json`

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

**400** – Validation failed

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**404** – Role not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/admin/roles/00000000-0000-4000-8000-000000000000/acl" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"features\": [
    \"string\"
  ]
}"
```

## GET `/customer_accounts/admin/users`

List customer users (admin)

Returns a paginated list of customer users with roles. Supports filtering by status, company, role, and search.

**Tags:** Customer Accounts Admin

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

### Responses

**200** – Paginated user list

Content-Type: `application/json`

```json
{
  "ok": true,
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "email": "string",
      "displayName": "string",
      "emailVerified": true,
      "isActive": true,
      "lockedUntil": null,
      "lastLoginAt": null,
      "customerEntityId": null,
      "personEntityId": null,
      "createdAt": "string",
      "roles": [
        {
          "id": "00000000-0000-4000-8000-000000000000",
          "name": "string",
          "slug": "string"
        }
      ]
    }
  ],
  "total": 1,
  "totalPages": 1,
  "page": 1
}
```

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/admin/users" \
  -H "Accept: application/json"
```

## POST `/customer_accounts/admin/users`

Create customer user (admin)

Creates a new customer user directly. Staff-initiated, bypasses signup flow.

**Tags:** Customer Accounts Admin

### Request Body

Content-Type: `application/json`

```json
{
  "email": "user@example.com",
  "password": "string",
  "displayName": "string"
}
```

### Responses

**201** – User created

Content-Type: `application/json`

```json
{
  "ok": true,
  "user": {
    "id": "00000000-0000-4000-8000-000000000000",
    "email": "string",
    "displayName": "string"
  }
}
```

**400** – Validation failed

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**409** – Email already exists

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/admin/users" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"email\": \"user@example.com\",
  \"password\": \"string\",
  \"displayName\": \"string\"
}"
```

## POST `/customer_accounts/admin/users-invite`

Invite customer user (admin)

Creates a staff-initiated invitation for a new customer user. The invitedByUserId is set from the staff auth context.

**Tags:** Customer Accounts Admin

### Request Body

Content-Type: `application/json`

```json
{
  "email": "user@example.com",
  "roleIds": [
    "00000000-0000-4000-8000-000000000000"
  ]
}
```

### Responses

**201** – Invitation created

Content-Type: `application/json`

```json
{
  "ok": true,
  "invitation": {
    "id": "00000000-0000-4000-8000-000000000000",
    "email": "string",
    "expiresAt": "string"
  }
}
```

**400** – Validation failed

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/admin/users-invite" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"email\": \"user@example.com\",
  \"roleIds\": [
    \"00000000-0000-4000-8000-000000000000\"
  ]
}"
```

## DELETE `/customer_accounts/admin/users/{id}`

Delete customer user (admin)

Soft deletes a customer user and revokes all their active sessions.

**Tags:** Customer Accounts Admin

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

### Responses

**200** – User deleted

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**404** – User not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/admin/users/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json"
```

## GET `/customer_accounts/admin/users/{id}`

Get customer user detail (admin)

Returns full customer user details including CRM links, roles, and active session count.

**Tags:** Customer Accounts Admin

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

### Responses

**200** – User detail

Content-Type: `application/json`

```json
{
  "ok": true,
  "user": {
    "id": "00000000-0000-4000-8000-000000000000",
    "email": "string",
    "displayName": "string",
    "emailVerified": true,
    "isActive": true,
    "lockedUntil": null,
    "lastLoginAt": null,
    "failedLoginAttempts": 1,
    "customerEntityId": null,
    "personEntityId": null,
    "createdAt": "string",
    "updatedAt": null,
    "roles": [
      {
        "id": "00000000-0000-4000-8000-000000000000",
        "name": "string",
        "slug": "string"
      }
    ],
    "activeSessionCount": 1
  }
}
```

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**404** – User not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/admin/users/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json"
```

## PUT `/customer_accounts/admin/users/{id}`

Update customer user (admin)

Updates a customer user. Staff can update status, lock, CRM links, and roles. Role assignment bypasses customer_assignable check.

**Tags:** Customer Accounts Admin

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

### Request Body

Content-Type: `application/json`

```json
{
  "lockedUntil": null,
  "personEntityId": null,
  "customerEntityId": null
}
```

### Responses

**200** – User updated

Content-Type: `application/json`

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

**400** – Validation failed or role not found

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**404** – User not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/admin/users/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"lockedUntil\": null,
  \"personEntityId\": null,
  \"customerEntityId\": null
}"
```

## POST `/customer_accounts/admin/users/{id}/reset-password`

Reset customer user password (admin)

Allows staff to set a new password for a customer user.

**Tags:** Customer Accounts Admin

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

### Request Body

Content-Type: `application/json`

```json
{
  "newPassword": "string"
}
```

### Responses

**200** – Password reset

Content-Type: `application/json`

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

**400** – Validation failed

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**404** – User not found

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/admin/users/00000000-0000-4000-8000-000000000000/reset-password" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"newPassword\": \"string\"
}"
```

## POST `/customer_accounts/admin/users/{id}/send-reset-link`

Send password reset link for customer user (admin)

Creates a password reset token for a customer user and returns a reset link URL. The admin must prepend the appropriate portal domain/slug to the relative URL.

**Tags:** Customer Accounts Admin

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

### Responses

**200** – Reset link generated

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**404** – User not found

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/admin/users/00000000-0000-4000-8000-000000000000/send-reset-link" \
  -H "Accept: application/json"
```

## POST `/customer_accounts/admin/users/{id}/verify-email`

Verify customer user email (admin)

Allows staff to manually mark a customer user email as verified.

**Tags:** Customer Accounts Admin

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

### Responses

**200** – Email verified

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**404** – User not found

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/admin/users/00000000-0000-4000-8000-000000000000/verify-email" \
  -H "Accept: application/json"
```

## POST `/customer_accounts/email/verify`

Verify customer email address

Validates the email verification token and marks the email as verified.

**Tags:** Customer Authentication

### Request Body

Content-Type: `application/json`

```json
{
  "token": "string"
}
```

### Responses

**200** – Email verified

Content-Type: `application/json`

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

**400** – Invalid or expired token

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/email/verify" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"token\": \"string\"
}"
```

## POST `/customer_accounts/invitations/accept`

Accept customer invitation

Accepts an invitation, creates the user account, assigns roles, and auto-logs in.

**Tags:** Customer Authentication

### Request Body

Content-Type: `application/json`

```json
{
  "token": "string",
  "password": "string",
  "displayName": "string"
}
```

### Responses

**201** – Invitation accepted and user created

Content-Type: `application/json`

```json
{
  "ok": true,
  "user": {
    "id": "00000000-0000-4000-8000-000000000000",
    "email": "user@example.com",
    "displayName": "string",
    "emailVerified": true
  },
  "resolvedFeatures": [
    "string"
  ]
}
```

**400** – Invalid or expired invitation

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/invitations/accept" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"token\": \"string\",
  \"password\": \"string\",
  \"displayName\": \"string\"
}"
```

## POST `/customer_accounts/login`

Authenticate customer credentials

Validates customer credentials and issues JWT + session cookies.

**Tags:** Customer Authentication

### Request Body

Content-Type: `application/json`

```json
{
  "email": "user@example.com",
  "password": "string"
}
```

### Responses

**200** – Login successful

Content-Type: `application/json`

```json
{
  "ok": true,
  "user": {
    "id": "00000000-0000-4000-8000-000000000000",
    "email": "user@example.com",
    "displayName": "string",
    "emailVerified": true
  },
  "resolvedFeatures": [
    "string"
  ]
}
```

**400** – Validation failed

Content-Type: `application/json`

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

**401** – Invalid credentials

Content-Type: `application/json`

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

**423** – Account locked

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://crmprod.erp.sobota.myopenmercato.com/customer_accounts/login" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"email\": \"user@example.com\",
  \"password\": \"string\"
}"
```

## POST `/customer_accounts/magic-link/request`

Request magic link login

Sends a magic link to the customer email. Always returns 200 to prevent enumeration.

**Tags:** Customer Authentication

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Request accepted

Content-Type: `application/json`

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

**429** – Too many requests

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/magic-link/request" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"email\": \"user@example.com\"
}"
```

## POST `/customer_accounts/magic-link/verify`

Verify magic link token

Validates the magic link token, auto-verifies email, and creates a session.

**Tags:** Customer Authentication

### Request Body

Content-Type: `application/json`

```json
{
  "token": "string"
}
```

### Responses

**200** – Login successful

Content-Type: `application/json`

```json
{
  "ok": true,
  "user": {
    "id": "00000000-0000-4000-8000-000000000000",
    "email": "user@example.com",
    "displayName": "string",
    "emailVerified": true
  },
  "resolvedFeatures": [
    "string"
  ]
}
```

**400** – Invalid or expired token

Content-Type: `application/json`

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

**401** – Account not found

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/magic-link/verify" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"token\": \"string\"
}"
```

## POST `/customer_accounts/password/reset-confirm`

Confirm customer password reset

Validates the reset token and sets a new password. Revokes all existing sessions.

**Tags:** Customer Authentication

### Request Body

Content-Type: `application/json`

```json
{
  "token": "string",
  "password": "string"
}
```

### Responses

**200** – Password reset successful

Content-Type: `application/json`

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

**400** – Invalid or expired token

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/password/reset-confirm" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"token\": \"string\",
  \"password\": \"string\"
}"
```

## POST `/customer_accounts/password/reset-request`

Request customer password reset

Initiates a password reset flow. Always returns 200 to prevent email enumeration.

**Tags:** Customer Authentication

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Request accepted

Content-Type: `application/json`

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

**429** – Too many requests

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/password/reset-request" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"email\": \"user@example.com\"
}"
```

## GET `/customer_accounts/portal/events/stream`

Subscribe to portal events via SSE (Portal Event Bridge)

Long-lived SSE connection that receives server-side events marked with portalBroadcast: true. Events are filtered by the customer's tenant and organization.

**Tags:** Customer Portal

### Responses

**200** – Event stream (text/event-stream)

Content-Type: `application/json`

**401** – Not authenticated

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/portal/events/stream" \
  -H "Accept: application/json"
```

## POST `/customer_accounts/portal/feature-check`

Check customer portal feature access

Checks which of the requested features the authenticated customer user has. Used by portal menu injection for feature-gating.

**Tags:** Customer Portal

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Feature check result

Content-Type: `application/json`

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

**400** – Invalid request

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/portal/feature-check" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"features\": [
    \"string\"
  ]
}"
```

## POST `/customer_accounts/portal/logout`

Customer logout

Revokes the current session and clears authentication cookies.

**Tags:** Customer Portal

### Responses

**200** – Logged out

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/portal/logout" \
  -H "Accept: application/json"
```

## GET `/customer_accounts/portal/notifications`

List customer notifications

Returns paginated notifications for the authenticated customer user. Dismissed notifications are excluded by default unless ?status=dismissed is specified.

**Tags:** Customer Portal

### Responses

**200** – Notification list

Content-Type: `application/json`

```json
{
  "ok": true,
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "type": "string",
      "title": "string",
      "body": null,
      "titleKey": null,
      "bodyKey": null,
      "titleVariables": null,
      "bodyVariables": null,
      "icon": null,
      "severity": "info",
      "status": "unread",
      "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
}
```

**401** – Not authenticated

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/portal/notifications" \
  -H "Accept: application/json"
```

## PUT `/customer_accounts/portal/notifications/{id}/dismiss`

Dismiss notification

Dismisses a single notification for the authenticated customer user.

**Tags:** Customer Portal

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

### Responses

**200** – Notification dismissed

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**404** – Notification not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/portal/notifications/00000000-0000-4000-8000-000000000000/dismiss" \
  -H "Accept: application/json"
```

## PUT `/customer_accounts/portal/notifications/{id}/read`

Mark notification as read

Marks a single notification as read for the authenticated customer user.

**Tags:** Customer Portal

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

### Responses

**200** – Notification marked as read

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**404** – Notification not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/portal/notifications/00000000-0000-4000-8000-000000000000/read" \
  -H "Accept: application/json"
```

## PUT `/customer_accounts/portal/notifications/mark-all-read`

Mark all notifications as read

Marks all unread notifications as read for the authenticated customer user.

**Tags:** Customer Portal

### Responses

**200** – All notifications marked as read

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/portal/notifications/mark-all-read" \
  -H "Accept: application/json"
```

## GET `/customer_accounts/portal/notifications/unread-count`

Get unread notification count

Returns the number of unread notifications for the authenticated customer user.

**Tags:** Customer Portal

### Responses

**200** – Unread count

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/portal/notifications/unread-count" \
  -H "Accept: application/json"
```

## POST `/customer_accounts/portal/password-change`

Change customer password

Changes the authenticated customer user password after verifying the current password.

**Tags:** Customer Portal

### Request Body

Content-Type: `application/json`

```json
{
  "currentPassword": "string",
  "newPassword": "string"
}
```

### Responses

**200** – Password changed

Content-Type: `application/json`

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

**400** – Current password incorrect or validation failed

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/portal/password-change" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"currentPassword\": \"string\",
  \"newPassword\": \"string\"
}"
```

## GET `/customer_accounts/portal/profile`

Get customer profile

Returns the authenticated customer user profile with roles and permissions.

**Tags:** Customer Portal

### Responses

**200** – Profile data

Content-Type: `application/json`

```json
{
  "ok": true,
  "user": {
    "id": "00000000-0000-4000-8000-000000000000",
    "email": "string",
    "displayName": "string",
    "emailVerified": true,
    "customerEntityId": null,
    "personEntityId": null,
    "isActive": true,
    "lastLoginAt": null,
    "createdAt": "string"
  },
  "roles": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "slug": "string"
    }
  ],
  "resolvedFeatures": [
    "string"
  ],
  "isPortalAdmin": true
}
```

**401** – Not authenticated

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/portal/profile" \
  -H "Accept: application/json"
```

## PUT `/customer_accounts/portal/profile`

Update customer profile

Updates the authenticated customer user profile.

**Tags:** Customer Portal

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Profile updated

Content-Type: `application/json`

```json
{
  "ok": true,
  "user": {
    "id": "00000000-0000-4000-8000-000000000000",
    "email": "string",
    "displayName": "string"
  }
}
```

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/portal/profile" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## GET `/customer_accounts/portal/sessions`

List customer sessions

Returns active sessions for the authenticated customer user.

**Tags:** Customer Portal

### Responses

**200** – Session list

Content-Type: `application/json`

```json
{
  "ok": true,
  "sessions": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "ipAddress": null,
      "userAgent": null,
      "lastUsedAt": null,
      "createdAt": "string",
      "expiresAt": "string",
      "isCurrent": true
    }
  ]
}
```

**401** – Not authenticated

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/portal/sessions" \
  -H "Accept: application/json"
```

## POST `/customer_accounts/portal/sessions-refresh`

Refresh customer JWT from session token

Uses the session cookie to issue a fresh JWT access token.

**Tags:** Customer Portal

### Responses

**200** – Token refreshed

Content-Type: `application/json`

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

**401** – Invalid session

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/portal/sessions-refresh" \
  -H "Accept: application/json"
```

## DELETE `/customer_accounts/portal/sessions/{id}`

Revoke a customer session

Revokes a specific session (not the current one).

**Tags:** Customer Portal

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

### Responses

**200** – Session revoked

Content-Type: `application/json`

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

**400** – Cannot revoke current session

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**404** – Session not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/portal/sessions/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json"
```

## GET `/customer_accounts/portal/users`

List company portal users

Lists all portal users associated with the same company.

**Tags:** Customer Portal

### Responses

**200** – User list

Content-Type: `application/json`

```json
{
  "ok": true,
  "users": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "email": "string",
      "displayName": "string",
      "emailVerified": true,
      "isActive": true,
      "lastLoginAt": null,
      "createdAt": "string",
      "roles": [
        {
          "id": "00000000-0000-4000-8000-000000000000",
          "name": "string",
          "slug": "string"
        }
      ]
    }
  ]
}
```

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/portal/users" \
  -H "Accept: application/json"
```

## POST `/customer_accounts/portal/users-invite`

Invite a user to the company portal

Creates an invitation for a new user to join the company portal.

**Tags:** Customer Portal

### Request Body

Content-Type: `application/json`

```json
{
  "email": "user@example.com",
  "roleIds": [
    "00000000-0000-4000-8000-000000000000"
  ]
}
```

### Responses

**201** – Invitation created

Content-Type: `application/json`

```json
{
  "ok": true,
  "invitation": {
    "id": "00000000-0000-4000-8000-000000000000",
    "email": "string",
    "expiresAt": "string"
  }
}
```

**400** – Validation failed

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions or non-assignable role

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/portal/users-invite" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"email\": \"user@example.com\",
  \"roleIds\": [
    \"00000000-0000-4000-8000-000000000000\"
  ]
}"
```

## DELETE `/customer_accounts/portal/users/{id}`

Delete a company portal user

Soft deletes a portal user and revokes all their sessions.

**Tags:** Customer Portal

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

### Responses

**200** – User deleted

Content-Type: `application/json`

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

**400** – Cannot delete self

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**404** – User not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/portal/users/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json"
```

## PUT `/customer_accounts/portal/users/{id}/roles`

Update portal user roles

Assigns new roles to a company portal user.

**Tags:** Customer Portal

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

### Request Body

Content-Type: `application/json`

```json
{
  "roleIds": [
    "00000000-0000-4000-8000-000000000000"
  ]
}
```

### Responses

**200** – Roles updated

Content-Type: `application/json`

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

**400** – Validation failed

Content-Type: `application/json`

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

**401** – Not authenticated

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**404** – User not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/portal/users/00000000-0000-4000-8000-000000000000/roles" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"roleIds\": [
    \"00000000-0000-4000-8000-000000000000\"
  ]
}"
```

## POST `/customer_accounts/signup`

Register a new customer account

Creates a new customer user account and sends an email verification token.

**Tags:** Customer Authentication

### Request Body

Content-Type: `application/json`

```json
{
  "email": "user@example.com",
  "password": "string",
  "displayName": "string"
}
```

### Responses

**201** – Account created successfully

Content-Type: `application/json`

```json
{
  "ok": true,
  "user": {
    "id": "00000000-0000-4000-8000-000000000000",
    "email": "user@example.com",
    "displayName": "string",
    "emailVerified": true
  }
}
```

**400** – Validation failed

Content-Type: `application/json`

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

**409** – Email already registered

Content-Type: `application/json`

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

**429** – Too many signup attempts

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/customer_accounts/signup" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"email\": \"user@example.com\",
  \"password\": \"string\",
  \"displayName\": \"string\"
}"
```

## DELETE `/customers/activities`

Delete activity

Deletes an activity identified by `id`. Accepts id via body or query string.

Requires features: customers.activities.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.manage

### 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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: customers.activities.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.view

### 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",
      "entityId": null,
      "dealId": null,
      "activityType": "string",
      "subject": null,
      "body": null,
      "occurredAt": null,
      "createdAt": null,
      "authorUserId": null,
      "organizationId": null,
      "tenantId": null,
      "activityTypeLabel": null,
      "authorName": null,
      "authorEmail": null,
      "appearanceIcon": null,
      "appearanceColor": null,
      "dealTitle": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/customers/activities?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/activities`

Create activity

Creates a timeline activity linked to an entity or deal.

Requires features: customers.activities.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.manage

### 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",
  "activityType": "string",
  "appearanceIcon": null,
  "appearanceColor": null
}
```

### Responses

**201** – Activity created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/customers/activities" \
  -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\",
  \"activityType\": \"string\",
  \"appearanceIcon\": null,
  \"appearanceColor\": null
}"
```

## PUT `/customers/activities`

Update activity

Updates subject, body, scheduling, or custom fields for an existing activity.

Requires features: customers.activities.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Activity updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/customers/activities" \
  -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/addresses`

Delete address

Deletes an address by id. The identifier may be included in the body or query.

Requires features: customers.activities.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.manage

### 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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: customers.activities.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| entityId | 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
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: customers.activities.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.manage

### 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"
}
```

### Responses

**201** – Address created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/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\"
}"
```

## PUT `/customers/addresses`

Update address

Updates fields on an existing customer address.

Requires features: customers.activities.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Address updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/customers/addresses" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## DELETE `/customers/comments`

Delete comment

Deletes a comment identified by `id` supplied via body or query string.

Requires features: customers.activities.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.manage

### 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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: customers.activities.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.view

### 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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: customers.activities.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.manage

### 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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: customers.activities.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.manage

### 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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: customers.companies.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.companies.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Company deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: customers.companies.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.companies.view

### 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 |
| 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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: customers.companies.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.companies.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "displayName": "string",
  "nextInteraction": null
}
```

### Responses

**201** – Company created

Content-Type: `application/json`

```json
{
  "id": null,
  "companyId": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/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\",
  \"nextInteraction\": null
}"
```

## PUT `/customers/companies`

Update company

Updates company profile fields, tags, or custom attributes.

Requires features: customers.companies.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.companies.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Company updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/customers/companies" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"nextInteraction\": null
}"
```

## GET `/customers/companies/{id}`

Fetch company with related data

Returns a company customer record with optional related resources such as addresses, comments, activities, deals, todos, and linked people.

**Tags:** Customers

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| include | query | any | Optional. Comma-separated list of relations to include (addresses, comments, activities, deals, todos, people). |

### Responses

**200** – Company detail payload

Content-Type: `application/json`

```json
{
  "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,
    "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
    }
  ],
  "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
    }
  ],
  "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://crmprod.erp.sobota.myopenmercato.com/customers/companies/:id" \
  -H "Accept: application/json"
```

## GET `/customers/dashboard/widgets/customer-todos`

Fetch recent customer todo links

Returns the most recently created todo links for display on dashboards.

Requires features: dashboards.view, customers.widgets.todos

**Tags:** Customers

**Requires authentication.**

**Features:** dashboards.view, customers.widgets.todos

### 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"
}
```

**500** – Widget failed to load

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: dashboards.view, customers.widgets.new-customers

**Tags:** Customers

**Requires authentication.**

**Features:** dashboards.view, customers.widgets.new-customers

### 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"
}
```

**500** – Widget failed to load

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: dashboards.view, customers.widgets.new-deals

**Tags:** Customers

**Requires authentication.**

**Features:** dashboards.view, customers.widgets.new-deals

### 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"
}
```

**500** – Widget failed to load

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: dashboards.view, customers.widgets.next-interactions

**Tags:** Customers

**Requires authentication.**

**Features:** dashboards.view, customers.widgets.next-interactions

### 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"
}
```

**500** – Widget failed to load

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: customers.deals.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.deals.manage

### 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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: customers.deals.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.deals.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| status | query | any | Optional |
| pipelineStage | query | any | Optional |
| pipelineId | query | any | Optional |
| pipelineStageId | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| personEntityId | query | any | Optional |
| companyEntityId | 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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: customers.deals.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.deals.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "title": "string"
}
```

### Responses

**201** – Deal created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/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\"
}"
```

## PUT `/customers/deals`

Update deal

Updates pipeline position, metadata, or associations for an existing deal.

Requires features: customers.deals.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.deals.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Deal updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/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/{id}`

Fetch deal with associations

Returns a deal with linked people, companies, custom fields, and viewer context.

**Tags:** Customers

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

### 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,
    "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
  }
}
```

**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://crmprod.erp.sobota.myopenmercato.com/customers/deals/:id" \
  -H "Accept: application/json"
```

## GET `/customers/dictionaries/{kind}`

List dictionary entries

Returns the merged dictionary entries for the requested kind, including inherited values.

Requires features: customers.people.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.people.view

### 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"
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: customers.settings.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.settings.manage

### 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"
}
```

**409** – Duplicate value conflict

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: customers.settings.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.settings.manage

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

### Responses

**200** – Entry deleted

Content-Type: `application/json`

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

**404** – Entry not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: customers.settings.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.settings.manage

### 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"
}
```

**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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: customers.people.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.people.view

### 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
    }
  ]
}
```

**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://crmprod.erp.sobota.myopenmercato.com/customers/dictionaries/currency" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/customers/people`

Delete person

Deletes a person by id. Request body or query may provide the identifier.

Requires features: customers.people.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.people.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Person deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: customers.people.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.people.view

### 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 |
| 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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: customers.people.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.people.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "nextInteraction": null,
  "firstName": "string",
  "lastName": "string",
  "companyEntityId": null
}
```

### Responses

**201** – Person created

Content-Type: `application/json`

```json
{
  "id": null,
  "personId": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/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\",
  \"nextInteraction\": null,
  \"firstName\": \"string\",
  \"lastName\": \"string\",
  \"companyEntityId\": null
}"
```

## PUT `/customers/people`

Update person

Updates contact details or custom fields for a person.

Requires features: customers.people.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.people.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Person updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/customers/people" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"nextInteraction\": 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, deals, and todos.

**Tags:** Customers

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | any | Required |
| include | query | any | Optional. Comma-separated list of relations to include (addresses, comments, activities, deals, todos). |

### Responses

**200** – Person detail payload

Content-Type: `application/json`

```json
{
  "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
    }
  ],
  "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
    }
  ],
  "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://crmprod.erp.sobota.myopenmercato.com/customers/people/:id" \
  -H "Accept: application/json"
```

## 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.

Requires features: customers.people.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.people.view

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

### Responses

**200** – Matching contact (if any)

Content-Type: `application/json`

```json
{
  "match": null
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: customers.pipelines.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.pipelines.manage

### 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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: customers.pipelines.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.pipelines.view

### 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"
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/customers/pipeline-stages" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/pipeline-stages`

Create pipeline stage

Creates a new pipeline stage.

Requires features: customers.pipelines.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.pipelines.manage

### 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"
}
```

### Responses

**201** – Stage created

Content-Type: `application/json`

```json
{
  "id": null
}
```

**400** – Validation failed

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/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\"
}"
```

## PUT `/customers/pipeline-stages`

Update pipeline stage

Updates an existing pipeline stage.

Requires features: customers.pipelines.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.pipelines.manage

### Request Body

Content-Type: `application/json`

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

### 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://crmprod.erp.sobota.myopenmercato.com/customers/pipeline-stages" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## POST `/customers/pipeline-stages/reorder`

Reorder pipeline stages

Updates the order of pipeline stages in bulk.

Requires features: customers.pipelines.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.pipelines.manage

### 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"
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: customers.pipelines.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.pipelines.manage

### 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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: customers.pipelines.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.pipelines.view

### 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"
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/customers/pipelines" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/customers/pipelines`

Create pipeline

Creates a new pipeline within the authenticated organization.

Requires features: customers.pipelines.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.pipelines.manage

### 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"
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: customers.pipelines.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.pipelines.manage

### 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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: customers.settings.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.settings.manage

### Responses

**200** – Current address format

Content-Type: `application/json`

```json
{
  "addressFormat": "string"
}
```

**400** – Organization context missing

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: customers.settings.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.settings.manage

### 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"
}
```

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/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\"
}"
```

## DELETE `/customers/tags`

Delete tag

Deletes a tag identified by `id`. The identifier may be provided via body or query string.

Requires features: customers.activities.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.manage

### 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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: customers.activities.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.view

### 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
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: customers.activities.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.manage

### 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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: customers.activities.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.manage

### 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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: customers.activities.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.manage

### 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"
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: customers.activities.manage

**Tags:** Customers

**Requires authentication.**

**Features:** customers.activities.manage

### 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"
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/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\"
}"
```

## GET `/customers/todos`

List customertodos

Returns a paginated collection of customertodos scoped to the authenticated organization.

Requires features: customers.view

**Tags:** Customers

**Requires authentication.**

**Features:** customers.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| all | 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,
      "todoOrganizationId": null,
      "organizationId": "string",
      "tenantId": "string",
      "createdAt": "string",
      "customer": {
        "id": null,
        "displayName": null,
        "kind": null
      }
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/customers/todos?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/dashboards/layout`

Load the current dashboard layout

Returns the saved widget layout together with the widgets the current user is allowed to place.

Requires features: dashboards.view

**Tags:** Dashboards

**Requires authentication.**

**Features:** dashboards.view

### Responses

**200** – Current dashboard layout and available widgets.

Content-Type: `application/json`

```json
{
  "layout": {
    "items": [
      {
        "id": "00000000-0000-4000-8000-000000000000",
        "widgetId": "string",
        "order": 1
      }
    ]
  },
  "allowedWidgetIds": [
    "string"
  ],
  "canConfigure": true,
  "context": {
    "userId": "00000000-0000-4000-8000-000000000000",
    "tenantId": null,
    "organizationId": null,
    "userName": null,
    "userEmail": null,
    "userLabel": "string"
  },
  "widgets": [
    {
      "id": "string",
      "title": "string",
      "description": null,
      "defaultSize": "sm",
      "defaultEnabled": true,
      "defaultSettings": null,
      "features": [
        "string"
      ],
      "moduleId": "string",
      "icon": null,
      "loaderKey": "string",
      "supportsRefresh": true
    }
  ]
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/dashboards/layout" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/dashboards/layout`

Persist dashboard layout changes

Saves the provided widget ordering, sizes, and settings for the current user.

Requires features: dashboards.configure

**Tags:** Dashboards

**Requires authentication.**

**Features:** dashboards.configure

### Request Body

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "widgetId": "string",
      "order": 1
    }
  ]
}
```

### Responses

**200** – Layout updated successfully.

Content-Type: `application/json`

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

**400** – Invalid layout payload

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/dashboards/layout" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"items\": [
    {
      \"id\": \"00000000-0000-4000-8000-000000000000\",
      \"widgetId\": \"string\",
      \"order\": 1
    }
  ]
}"
```

## PATCH `/dashboards/layout/{itemId}`

Update a dashboard layout item

Adjusts the size or settings for a single widget within the dashboard layout.

Requires features: dashboards.configure

**Tags:** Dashboards

**Requires authentication.**

**Features:** dashboards.configure

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

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Layout item updated.

Content-Type: `application/json`

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

**400** – Invalid payload or missing item id

Content-Type: `application/json`

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

**404** – Item not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PATCH "https://crmprod.erp.sobota.myopenmercato.com/dashboards/layout/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## GET `/dashboards/roles/widgets`

Fetch widget assignments for a role

Returns the widgets explicitly assigned to the given role together with the evaluation scope.

Requires features: dashboards.admin.assign-widgets

**Tags:** Dashboards

**Requires authentication.**

**Features:** dashboards.admin.assign-widgets

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

### Responses

**200** – Current widget configuration for the role.

Content-Type: `application/json`

```json
{
  "widgetIds": [
    "string"
  ],
  "hasCustom": true,
  "scope": {
    "tenantId": null,
    "organizationId": null
  }
}
```

**400** – Missing role identifier

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/dashboards/roles/widgets?roleId=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/dashboards/roles/widgets`

Update widgets assigned to a role

Persists the widget list for a role within the provided tenant and organization scope.

Requires features: dashboards.admin.assign-widgets

**Tags:** Dashboards

**Requires authentication.**

**Features:** dashboards.admin.assign-widgets

### Request Body

Content-Type: `application/json`

```json
{
  "roleId": "00000000-0000-4000-8000-000000000000",
  "tenantId": null,
  "organizationId": null,
  "widgetIds": [
    "string"
  ]
}
```

### Responses

**200** – Widgets updated successfully.

Content-Type: `application/json`

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

**400** – Invalid payload or unknown widgets

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/dashboards/roles/widgets" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"roleId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": null,
  \"organizationId\": null,
  \"widgetIds\": [
    \"string\"
  ]
}"
```

## GET `/dashboards/users/widgets`

Read widget overrides for a user

Returns the widgets inherited and explicitly configured for the requested user within the current scope.

Requires features: dashboards.admin.assign-widgets

**Tags:** Dashboards

**Requires authentication.**

**Features:** dashboards.admin.assign-widgets

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

### Responses

**200** – Widget settings for the user.

Content-Type: `application/json`

```json
{
  "mode": "inherit",
  "widgetIds": [
    "string"
  ],
  "hasCustom": true,
  "effectiveWidgetIds": [
    "string"
  ],
  "scope": {
    "tenantId": null,
    "organizationId": null
  }
}
```

**400** – Missing user identifier

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/dashboards/users/widgets?userId=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/dashboards/users/widgets`

Update user-specific dashboard widgets

Sets the widget override mode and allowed widgets for a user. Passing `mode: inherit` clears overrides.

Requires features: dashboards.admin.assign-widgets

**Tags:** Dashboards

**Requires authentication.**

**Features:** dashboards.admin.assign-widgets

### Request Body

Content-Type: `application/json`

```json
{
  "userId": "00000000-0000-4000-8000-000000000000",
  "tenantId": null,
  "organizationId": null,
  "mode": "inherit",
  "widgetIds": [
    "string"
  ]
}
```

### Responses

**200** – Overrides saved.

Content-Type: `application/json`

```json
{
  "ok": true,
  "mode": "inherit",
  "widgetIds": [
    "string"
  ]
}
```

**400** – Invalid payload or unknown widgets

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/dashboards/users/widgets" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"userId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": null,
  \"organizationId\": null,
  \"mode\": \"inherit\",
  \"widgetIds\": [
    \"string\"
  ]
}"
```

## GET `/dashboards/widgets/catalog`

List available dashboard widgets

Returns the catalog of widgets that modules expose, including defaults and feature requirements.

Requires features: dashboards.admin.assign-widgets

**Tags:** Dashboards

**Requires authentication.**

**Features:** dashboards.admin.assign-widgets

### Responses

**200** – Widgets available for assignment.

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "title": "string",
      "description": null,
      "defaultSize": "sm",
      "defaultEnabled": true,
      "defaultSettings": null,
      "features": [
        "string"
      ],
      "moduleId": "string",
      "icon": null,
      "loaderKey": "string",
      "supportsRefresh": true
    }
  ]
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/dashboards/widgets/catalog" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/dashboards/widgets/data`

Fetch aggregated data for dashboard widgets

Executes an aggregation query against the specified entity type and returns the result. Supports date range filtering, grouping, and period-over-period comparison.

Requires features: analytics.view

**Tags:** Dashboards

**Requires authentication.**

**Features:** analytics.view

### Request Body

Content-Type: `application/json`

```json
{
  "entityType": "string",
  "metric": {
    "field": "string",
    "aggregate": "count"
  }
}
```

### Responses

**200** – Aggregated data for the widget.

Content-Type: `application/json`

```json
{
  "value": null,
  "data": [
    {
      "value": null
    }
  ],
  "metadata": {
    "fetchedAt": "string",
    "recordCount": 1
  }
}
```

**400** – Invalid request payload

Content-Type: `application/json`

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

**500** – Internal server error

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/dashboards/widgets/data" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityType\": \"string\",
  \"metric\": {
    \"field\": \"string\",
    \"aggregate\": \"count\"
  }
}"
```

## GET `/data_sync/mappings`

List or create field mappings

Requires features: data_sync.configure

**Tags:** Data Sync

**Requires authentication.**

**Features:** data_sync.configure

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/data_sync/mappings" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/data_sync/mappings`

List or create field mappings

Requires features: data_sync.configure

**Tags:** Data Sync

**Requires authentication.**

**Features:** data_sync.configure

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/data_sync/mappings" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/data_sync/mappings/{id}`

Get, update, or delete a field mapping

Requires features: data_sync.configure

**Tags:** Data Sync

**Requires authentication.**

**Features:** data_sync.configure

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

### Responses

**204** – Success

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/data_sync/mappings/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/data_sync/mappings/{id}`

Get, update, or delete a field mapping

Requires features: data_sync.configure

**Tags:** Data Sync

**Requires authentication.**

**Features:** data_sync.configure

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/data_sync/mappings/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/data_sync/mappings/{id}`

Get, update, or delete a field mapping

Requires features: data_sync.configure

**Tags:** Data Sync

**Requires authentication.**

**Features:** data_sync.configure

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/data_sync/mappings/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/data_sync/options`

List data sync integration options

Requires features: data_sync.view

**Tags:** Data Sync

**Requires authentication.**

**Features:** data_sync.view

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/data_sync/options" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/data_sync/run`

Start a data sync run

Requires features: data_sync.run

**Tags:** Data Sync

**Requires authentication.**

**Features:** data_sync.run

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/data_sync/run" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/data_sync/runs`

List sync runs

Requires features: data_sync.view

**Tags:** Data Sync

**Requires authentication.**

**Features:** data_sync.view

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/data_sync/runs" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/data_sync/runs/{id}`

Get sync run detail

Requires features: data_sync.view

**Tags:** Data Sync

**Requires authentication.**

**Features:** data_sync.view

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/data_sync/runs/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/data_sync/runs/{id}/cancel`

Cancel a running sync

Requires features: data_sync.run

**Tags:** Data Sync

**Requires authentication.**

**Features:** data_sync.run

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

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/data_sync/runs/:id/cancel" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/data_sync/runs/{id}/retry`

Retry a failed sync run

Requires features: data_sync.run

**Tags:** Data Sync

**Requires authentication.**

**Features:** data_sync.run

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

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/data_sync/runs/:id/retry" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/data_sync/schedules`

List or create sync schedules

Requires features: data_sync.configure

**Tags:** Data Sync

**Requires authentication.**

**Features:** data_sync.configure

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/data_sync/schedules" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/data_sync/schedules`

List or create sync schedules

Requires features: data_sync.configure

**Tags:** Data Sync

**Requires authentication.**

**Features:** data_sync.configure

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/data_sync/schedules" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/data_sync/schedules/{id}`

Manage a sync schedule

Requires features: data_sync.configure

**Tags:** Data Sync

**Requires authentication.**

**Features:** data_sync.configure

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

### Responses

**204** – Success

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/data_sync/schedules/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/data_sync/schedules/{id}`

Manage a sync schedule

Requires features: data_sync.configure

**Tags:** Data Sync

**Requires authentication.**

**Features:** data_sync.configure

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/data_sync/schedules/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/data_sync/schedules/{id}`

Manage a sync schedule

Requires features: data_sync.configure

**Tags:** Data Sync

**Requires authentication.**

**Features:** data_sync.configure

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/data_sync/schedules/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/data_sync/validate`

Validate sync connection

Requires features: data_sync.configure

**Tags:** Data Sync

**Requires authentication.**

**Features:** data_sync.configure

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/data_sync/validate" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/dictionaries`

List dictionaries

Returns dictionaries accessible to the current organization, optionally including inactive records.

Requires features: dictionaries.view

**Tags:** Dictionaries

**Requires authentication.**

**Features:** dictionaries.view

### 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
    }
  ]
}
```

**500** – Failed to load dictionaries

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/dictionaries" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/dictionaries`

Create dictionary

Registers a dictionary scoped to the current organization.

Requires features: dictionaries.manage

**Tags:** Dictionaries

**Requires authentication.**

**Features:** dictionaries.manage

### 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"
}
```

**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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: dictionaries.manage

**Tags:** Dictionaries

**Requires authentication.**

**Features:** dictionaries.manage

### 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"
}
```

**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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: dictionaries.view

**Tags:** Dictionaries

**Requires authentication.**

**Features:** dictionaries.view

### 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"
}
```

**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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: dictionaries.manage

**Tags:** Dictionaries

**Requires authentication.**

**Features:** dictionaries.manage

### 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"
}
```

**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://crmprod.erp.sobota.myopenmercato.com/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 alphabetically.

Requires features: dictionaries.view

**Tags:** Dictionaries

**Requires authentication.**

**Features:** dictionaries.view

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

### Responses

**200** – Dictionary entries.

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "value": "string",
      "label": "string",
      "color": null,
      "icon": null,
      "createdAt": "string",
      "updatedAt": null
    }
  ]
}
```

**400** – Invalid parameters

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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: dictionaries.manage

**Tags:** Dictionaries

**Requires authentication.**

**Features:** dictionaries.manage

### 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,
  "createdAt": "string",
  "updatedAt": null
}
```

**400** – Validation failed

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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: dictionaries.manage

**Tags:** Dictionaries

**Requires authentication.**

**Features:** dictionaries.manage

### 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"
}
```

**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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: dictionaries.manage

**Tags:** Dictionaries

**Requires authentication.**

**Features:** dictionaries.manage

### 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,
  "createdAt": "string",
  "updatedAt": null
}
```

**400** – Validation failed

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://crmprod.erp.sobota.myopenmercato.com/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
}"
```

## 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,
  "tenantId": null,
  "tenants": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "isActive": true
    }
  ],
  "isSuperAdmin": true
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/directory/organization-switcher" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/directory/organizations`

Delete organization

Soft deletes an organization identified by id.

Requires features: directory.organizations.manage

**Tags:** Directory

**Requires authentication.**

**Features:** directory.organizations.manage

### 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"
}
```

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: directory.organizations.view

**Tags:** Directory

**Requires authentication.**

**Features:** directory.organizations.view

### 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"
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: directory.organizations.manage

**Tags:** Directory

**Requires authentication.**

**Features:** directory.organizations.manage

### Request Body

Content-Type: `application/json`

```json
{
  "name": "string",
  "slug": 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"
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/directory/organizations" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"name\": \"string\",
  \"slug\": null,
  \"parentId\": null
}"
```

## PUT `/directory/organizations`

Update organization

Updates organization details and hierarchy assignments.

Requires features: directory.organizations.manage

**Tags:** Directory

**Requires authentication.**

**Features:** directory.organizations.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Organization updated.

Content-Type: `application/json`

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

**400** – Validation failed

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/directory/organizations" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"slug\": null,
  \"parentId\": null
}"
```

## GET `/directory/organizations/lookup`

GET /directory/organizations/lookup

**Tags:** Directory (Tenants & Organizations)

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/directory/organizations/lookup" \
  -H "Accept: application/json"
```

## DELETE `/directory/tenants`

Delete tenant

Soft deletes the tenant identified by id.

Requires features: directory.tenants.manage

**Tags:** Directory

**Requires authentication.**

**Features:** directory.tenants.manage

### 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"
}
```

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: directory.tenants.view

**Tags:** Directory

**Requires authentication.**

**Features:** directory.tenants.view

### 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"
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: directory.tenants.manage

**Tags:** Directory

**Requires authentication.**

**Features:** directory.tenants.manage

### 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"
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: directory.tenants.manage

**Tags:** Directory

**Requires authentication.**

**Features:** directory.tenants.manage

### 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"
}
```

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/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`

GET /directory/tenants/lookup

**Tags:** Directory (Tenants & Organizations)

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: entities.definitions.manage

**Tags:** Entities

**Requires authentication.**

**Features:** entities.definitions.manage

### Request Body

Content-Type: `application/json`

```json
{
  "entityId": "string",
  "key": "string"
}
```

### Responses

**200** – Definition deleted

Content-Type: `application/json`

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

**400** – Missing entity id or key

Content-Type: `application/json`

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

**404** – Definition not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/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"
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: entities.definitions.manage

**Tags:** Entities

**Requires authentication.**

**Features:** entities.definitions.manage

### 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"
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: entities.definitions.manage

**Tags:** Entities

**Requires authentication.**

**Features:** entities.definitions.manage

### 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
}
```

**400** – Validation error

Content-Type: `application/json`

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

**500** – Unexpected failure

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: entities.definitions.manage

**Tags:** Entities

**Requires authentication.**

**Features:** entities.definitions.manage

### 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"
  ]
}
```

**400** – Missing entity id

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: entities.definitions.manage

**Tags:** Entities

**Requires authentication.**

**Features:** entities.definitions.manage

### 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"
}
```

**404** – Definition not found

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: entities.definitions.manage

**Tags:** Entities

**Requires authentication.**

**Features:** entities.definitions.manage

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

### Responses

**200** – Map

Content-Type: `application/json`

```json
{
  "entityId": "string",
  "fields": [
    {
      "field": "string",
      "hashField": null
    }
  ]
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: entities.definitions.manage

**Tags:** Entities

**Requires authentication.**

**Features:** entities.definitions.manage

### 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
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: entities.definitions.manage

**Tags:** Entities

**Requires authentication.**

**Features:** entities.definitions.manage

### 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"
}
```

**404** – Entity not found in scope

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/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
    }
  ]
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: entities.definitions.manage

**Tags:** Entities

**Requires authentication.**

**Features:** entities.definitions.manage

### Request Body

Content-Type: `application/json`

```json
{
  "entityId": "string",
  "label": "string",
  "description": null,
  "showInSidebar": 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"
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/entities/entities" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"entityId\": \"string\",
  \"label\": \"string\",
  \"description\": null,
  \"showInSidebar\": false
}"
```

## DELETE `/entities/records`

Delete record

Soft deletes the specified record within the current tenant/org scope.

Requires features: entities.records.manage

**Tags:** Entities

**Requires authentication.**

**Features:** entities.records.manage

### 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"
}
```

**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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: entities.records.view

**Tags:** Entities

**Requires authentication.**

**Features:** entities.records.view

### 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 |
| 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"
}
```

**500** – Unexpected failure

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: entities.records.manage

**Tags:** Entities

**Requires authentication.**

**Features:** entities.records.manage

### 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"
}
```

**500** – Unexpected failure

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: entities.records.manage

**Tags:** Entities

**Requires authentication.**

**Features:** entities.records.manage

### 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"
}
```

**500** – Unexpected failure

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/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 50 option entries for populating relation dropdowns, automatically resolving label fields when omitted.

Requires features: entities.definitions.view

**Tags:** Entities

**Requires authentication.**

**Features:** entities.definitions.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| entityId | query | any | Required |
| labelField | query | any | Optional |
| q | query | any | Optional |

### Responses

**200** – Option list

Content-Type: `application/json`

```json
{
  "items": [
    {
      "value": "string",
      "label": "string"
    }
  ]
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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"
    }
  ]
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/entities/sidebar-entities" \
  -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://crmprod.erp.sobota.myopenmercato.com/events/stream" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/example/assignees`

List example assignees

Returns mock assignee options filtered by the optional `q` query parameter.

Requires features: example.todos.view

**Tags:** Example

**Requires authentication.**

**Features:** example.todos.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| q | query | any | Optional |

### Responses

**200** – Assignable users.

Content-Type: `application/json`

```json
{
  "items": [
    {
      "value": "string",
      "label": "string"
    }
  ]
}
```

**500** – Unexpected server error

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/example/assignees" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/example/assignees`

Emit SSE probe event for integration tests

Emits a clientBroadcast example todo event with optional recipient filters (user/role/org).

Requires features: example.todos.manage

**Tags:** Example

**Requires authentication.**

**Features:** example.todos.manage

### Responses

**200** – Event emitted

Content-Type: `application/json`

```json
{
  "ok": true,
  "eventId": "string",
  "payload": {}
}
```

**400** – Invalid payload

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/example/assignees" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/example/blog/{id}`

Fetch demo blog payload

Returns a placeholder blog record containing the provided identifier.

**Tags:** Example

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

### Responses

**200** – Placeholder blog payload.

Content-Type: `application/json`

```json
{
  "id": "string",
  "method": "GET"
}
```

**401** – Authentication required

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/example/blog/string" \
  -H "Accept: application/json"
```

## POST `/example/blog/{id}`

Create demo blog payload

Echoes the provided identifier as a placeholder write endpoint.

**Tags:** Example

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

### Responses

**200** – Placeholder confirmation.

Content-Type: `application/json`

```json
{
  "id": "string",
  "method": "POST"
}
```

**401** – Authentication required

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/example/blog/string" \
  -H "Accept: application/json"
```

## DELETE `/example/customer-priorities`

Delete customer priority

Soft-deletes a customer priority record.

Requires features: example.todos.manage

**Tags:** Example

**Requires authentication.**

**Features:** example.todos.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Customer Priority deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/example/customer-priorities" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/example/customer-priorities`

List customer priorities

Returns a paginated collection of customer priorities in the current tenant scope.

Requires features: example.view

**Tags:** Example

**Requires authentication.**

**Features:** example.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | query | any | Optional |
| customerId | query | any | Optional |
| page | query | any | Optional |
| pageSize | 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 customer priorities

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "customer_id": "00000000-0000-4000-8000-000000000000",
      "priority": "low",
      "tenant_id": null,
      "organization_id": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/example/customer-priorities?page=1&pageSize=50&sortField=created_at&sortDir=desc" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/example/customer-priorities`

Create customer priority

Creates or stores customer priority records for injected CRUD fields.

Requires features: example.todos.manage

**Tags:** Example

**Requires authentication.**

**Features:** example.todos.manage

### Request Body

Content-Type: `application/json`

```json
{
  "customerId": "00000000-0000-4000-8000-000000000000",
  "priority": "normal"
}
```

### Responses

**201** – Customer Priority created

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/example/customer-priorities" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"customerId\": \"00000000-0000-4000-8000-000000000000\",
  \"priority\": \"normal\"
}"
```

## PUT `/example/customer-priorities`

Update customer priority

Updates customer priority values.

Requires features: example.todos.manage

**Tags:** Example

**Requires authentication.**

**Features:** example.todos.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Customer Priority updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/example/customer-priorities" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## POST `/example/notifications`

Emit example actionable notification

Requires features: example.todos.manage

**Tags:** Example

**Requires authentication.**

**Features:** example.todos.manage

### Request Body

Content-Type: `application/json`

No example available for this content type.

### Responses

**201** – Notification emitted

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/example/notifications" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/example/organizations`

Resolve organization labels

Fetches organization names for the provided identifiers within the current tenant scope.

Requires features: example.todos.view

**Tags:** Example

**Requires authentication.**

**Features:** example.todos.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| ids | query | any | Optional |

### Responses

**200** – Resolved organizations.

Content-Type: `application/json`

```json
{
  "items": [
    {
      "value": "string",
      "label": "string"
    }
  ]
}
```

**500** – Unexpected server error

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/example/organizations" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/example/qa-events`

Clear QA-captured server events for the current tenant scope

Requires features: example.view

**Tags:** Example

**Requires authentication.**

**Features:** example.view

### Responses

**200** – Captured events cleared

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/example/qa-events" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/example/qa-events`

List QA-captured server events for the current tenant scope

Requires features: example.view

**Tags:** Example

**Requires authentication.**

**Features:** example.view

### Responses

**200** – Captured events

Content-Type: `application/json`

```json
{
  "items": [
    {
      "event": "string",
      "payload": {},
      "capturedAt": "string"
    }
  ]
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/example/qa-events" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/example/tags`

List example tags

Returns tag options collected from custom field values and dictionary configuration.

Requires features: example.todos.view

**Tags:** Example

**Requires authentication.**

**Features:** example.todos.view

### Responses

**200** – Available tag options.

Content-Type: `application/json`

```json
{
  "items": [
    {
      "value": "string",
      "label": "string"
    }
  ]
}
```

**500** – Failed to resolve tags

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/example/tags" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/example/todos`

Delete todo

Deletes a todo by id. Provide the identifier in the request body.

Requires features: example.todos.manage

**Tags:** Example

**Requires authentication.**

**Features:** example.todos.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Todo deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/example/todos" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/example/todos`

List todos

Returns a paginated collection of todos in the current tenant scope.

Requires features: example.todos.view

**Tags:** Example

**Requires authentication.**

**Features:** example.todos.view

### 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 |
| title | query | any | Optional |
| isDone | query | any | Optional |
| withDeleted | query | any | Optional |
| organizationId | query | any | Optional |
| createdFrom | query | any | Optional |
| createdTo | query | any | Optional |
| format | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated todos

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "title": "string",
      "tenant_id": null,
      "organization_id": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/example/todos?page=1&pageSize=50&sortField=id&sortDir=asc&withDeleted=false" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/example/todos`

Create todo

Creates a todo record. Supports additional custom field keys prefixed with `cf_`.

Requires features: example.todos.manage

**Tags:** Example

**Requires authentication.**

**Features:** example.todos.manage

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**201** – Todo created

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/example/todos" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## PUT `/example/todos`

Update todo

Updates an existing todo record by id. Accepts base fields and optional `cf_` custom fields.

Requires features: example.todos.manage

**Tags:** Example

**Requires authentication.**

**Features:** example.todos.manage

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Todo updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/example/todos" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## 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"
}
```

**404** – Tenant not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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"
}
```

**404** – Tenant not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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"
}
```

**404** – Tenant not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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"
}
```

**404** – Tenant not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires roles: superadmin

**Tags:** Feature Toggles

**Requires authentication.**

**Roles:** superadmin

### 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"
}
```

**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://crmprod.erp.sobota.myopenmercato.com/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.

Requires roles: superadmin

**Tags:** Feature Toggles

**Requires authentication.**

**Roles:** superadmin

### 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
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

**400** – Invalid query parameters

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://crmprod.erp.sobota.myopenmercato.com/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.

Requires roles: superadmin

**Tags:** Feature Toggles

**Requires authentication.**

**Roles:** superadmin

### 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"
}
```

**403** – Forbidden - superadmin role required

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires roles: superadmin

**Tags:** Feature Toggles

**Requires authentication.**

**Roles:** superadmin

### 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"
}
```

**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://crmprod.erp.sobota.myopenmercato.com/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.

Requires roles: superadmin

**Tags:** Feature Toggles

**Requires authentication.**

**Roles:** superadmin

### 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
}
```

**400** – Invalid identifier

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://crmprod.erp.sobota.myopenmercato.com/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.

Requires roles: superadmin

**Tags:** Feature Toggles

**Requires authentication.**

**Roles:** superadmin

### 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"
}
```

**400** – Invalid request

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://crmprod.erp.sobota.myopenmercato.com/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.

Requires roles: superadmin

**Tags:** Feature Toggles

**Requires authentication.**

**Roles:** superadmin

### 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",
      "overrideState": "enabled",
      "identifier": "string",
      "name": "string",
      "category": null,
      "defaultState": true,
      "tenantName": null
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1,
  "isSuperAdmin": true
}
```

**400** – Invalid query parameters

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires roles: superadmin

**Tags:** Feature Toggles

**Requires authentication.**

**Roles:** superadmin

### 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"
}
```

**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://crmprod.erp.sobota.myopenmercato.com/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 `/inbox_ops/emails`

List received emails

Processing log of all received emails

Requires features: inbox_ops.log.view

**Tags:** InboxOps

**Requires authentication.**

**Features:** inbox_ops.log.view

### Responses

**200** – Paginated list of emails

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/inbox_ops/emails" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/inbox_ops/emails/{id}`

Soft-delete an inbox email

Requires features: inbox_ops.proposals.manage

**Tags:** InboxOps

**Requires authentication.**

**Features:** inbox_ops.proposals.manage

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

### Responses

**200** – Email deleted

Content-Type: `application/json`

**404** – Email not found

Content-Type: `application/json`

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/inbox_ops/emails/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/inbox_ops/emails/{id}`

Get email detail with parsed thread

Requires features: inbox_ops.log.view

**Tags:** InboxOps

**Requires authentication.**

**Features:** inbox_ops.log.view

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

### Responses

**200** – Email detail

Content-Type: `application/json`

**404** – Email not found

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/inbox_ops/emails/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/inbox_ops/emails/{id}/reprocess`

Re-trigger LLM extraction on a failed or low-confidence email

Requires features: inbox_ops.proposals.manage

**Tags:** InboxOps

**Requires authentication.**

**Features:** inbox_ops.proposals.manage

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

### Responses

**200** – Email queued for reprocessing

Content-Type: `application/json`

**404** – Email not found

Content-Type: `application/json`

**409** – Email is already processing or proposal cannot be superseded safely

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/inbox_ops/emails/:id/reprocess" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/inbox_ops/extract`

Submit raw text for LLM extraction

Creates an InboxEmail record from raw text and triggers the extraction pipeline. The extraction runs asynchronously.

Requires features: inbox_ops.proposals.manage

**Tags:** InboxOps

**Requires authentication.**

**Features:** inbox_ops.proposals.manage

### Responses

**200** – Extraction queued successfully

Content-Type: `application/json`

**400** – Invalid request body

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/inbox_ops/extract" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/inbox_ops/proposals`

List proposals

List inbox proposals with optional status filter and pagination

Requires features: inbox_ops.proposals.view

**Tags:** InboxOps

**Requires authentication.**

**Features:** inbox_ops.proposals.view

### Responses

**200** – Paginated list of proposals

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/inbox_ops/proposals" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/inbox_ops/proposals/{id}`

Get proposal detail

Returns proposal with actions, discrepancies, and source email

Requires features: inbox_ops.proposals.view

**Tags:** InboxOps

**Requires authentication.**

**Features:** inbox_ops.proposals.view

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

### Responses

**200** – Full proposal detail

Content-Type: `application/json`

**404** – Proposal not found

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/inbox_ops/proposals/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/inbox_ops/proposals/{id}/accept-all`

Accept and execute all pending actions in a proposal

Requires features: inbox_ops.proposals.manage

**Tags:** InboxOps

**Requires authentication.**

**Features:** inbox_ops.proposals.manage

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

### Responses

**200** – All actions processed

Content-Type: `application/json`

**404** – Proposal not found

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/inbox_ops/proposals/:id/accept-all" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PATCH `/inbox_ops/proposals/{id}/actions/{actionId}`

Edit action payload before accepting

Requires features: inbox_ops.proposals.manage

**Tags:** InboxOps

**Requires authentication.**

**Features:** inbox_ops.proposals.manage

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

### Responses

**200** – Action updated

Content-Type: `application/json`

**404** – Action not found

Content-Type: `application/json`

**409** – Action already processed

Content-Type: `application/json`

### Example

```bash
curl -X PATCH "https://crmprod.erp.sobota.myopenmercato.com/inbox_ops/proposals/:id/actions/:actionId" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/inbox_ops/proposals/{id}/actions/{actionId}/accept`

Accept and execute a proposal action

Executes the action and creates the entity in the target module. Returns 409 if already processed.

Requires features: inbox_ops.proposals.manage

**Tags:** InboxOps

**Requires authentication.**

**Features:** inbox_ops.proposals.manage

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

### Responses

**200** – Action executed successfully

Content-Type: `application/json`

**404** – Action not found

Content-Type: `application/json`

**409** – Action already processed

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/inbox_ops/proposals/:id/actions/:actionId/accept" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PATCH `/inbox_ops/proposals/{id}/actions/{actionId}/complete`

Mark an action as completed with an externally-created entity

Used when an action is fulfilled through the normal sales form instead of the execution engine. Updates the action status without running the execution engine.

Requires features: inbox_ops.proposals.manage

**Tags:** InboxOps

**Requires authentication.**

**Features:** inbox_ops.proposals.manage

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

### Responses

**200** – Action marked as completed

Content-Type: `application/json`

**400** – Invalid body

Content-Type: `application/json`

**404** – Action not found

Content-Type: `application/json`

**409** – Action already processed

Content-Type: `application/json`

### Example

```bash
curl -X PATCH "https://crmprod.erp.sobota.myopenmercato.com/inbox_ops/proposals/:id/actions/:actionId/complete" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/inbox_ops/proposals/{id}/actions/{actionId}/reject`

Reject a proposal action

Requires features: inbox_ops.proposals.manage

**Tags:** InboxOps

**Requires authentication.**

**Features:** inbox_ops.proposals.manage

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

### Responses

**200** – Action rejected

Content-Type: `application/json`

**404** – Action not found

Content-Type: `application/json`

**409** – Action already processed

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/inbox_ops/proposals/:id/actions/:actionId/reject" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/inbox_ops/proposals/{id}/categorize`

Set or change the category of a proposal

Assigns a category to a proposal. Returns the new and previous category for undo support.

Requires features: inbox_ops.proposals.manage

**Tags:** InboxOps

**Requires authentication.**

**Features:** inbox_ops.proposals.manage

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

### Responses

**200** – Category updated

Content-Type: `application/json`

**400** – Invalid category value

Content-Type: `application/json`

**404** – Proposal not found

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/inbox_ops/proposals/:id/categorize" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/inbox_ops/proposals/{id}/reject`

Reject entire proposal (all pending actions)

Requires features: inbox_ops.proposals.manage

**Tags:** InboxOps

**Requires authentication.**

**Features:** inbox_ops.proposals.manage

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

### Responses

**200** – Proposal rejected

Content-Type: `application/json`

**404** – Proposal not found

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/inbox_ops/proposals/:id/reject" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/inbox_ops/proposals/{id}/replies/{replyId}/send`

Send a draft reply email and register it in messages when available

Sends the draft_reply action payload via the configured email provider. When the messages module is available, also records the sent reply as an internal message record. Sets In-Reply-To and References headers for threading.

Requires features: inbox_ops.replies.send

**Tags:** InboxOps

**Requires authentication.**

**Features:** inbox_ops.replies.send

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

### Responses

**200** – Reply sent successfully

Content-Type: `application/json`

**400** – Missing required payload fields

Content-Type: `application/json`

**404** – Reply action not found

Content-Type: `application/json`

**409** – Action in invalid state for sending

Content-Type: `application/json`

**502** – Email delivery failed

Content-Type: `application/json`

**503** – Email service not configured or disabled

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/inbox_ops/proposals/:id/replies/:replyId/send" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/inbox_ops/proposals/{id}/translate`

Translate proposal content

Translates the proposal summary and action descriptions to the target locale. Results are cached.

Requires features: inbox_ops.proposals.view

**Tags:** InboxOps

**Requires authentication.**

**Features:** inbox_ops.proposals.view

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

### Responses

**200** – Translation result

Content-Type: `application/json`

**400** – Invalid target locale or same language

Content-Type: `application/json`

**404** – Proposal not found

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/inbox_ops/proposals/:id/translate" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/inbox_ops/proposals/counts`

Get proposal status and category counts

Returns counts by status and by category for tab badges and filter dropdowns

Requires features: inbox_ops.proposals.view

**Tags:** InboxOps

**Requires authentication.**

**Features:** inbox_ops.proposals.view

### Responses

**200** – Status and category counts object

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/inbox_ops/proposals/counts" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/inbox_ops/settings`

Get tenant inbox configuration

Returns the forwarding address and configuration for this tenant

Requires features: inbox_ops.settings.manage

**Tags:** InboxOps

**Requires authentication.**

**Features:** inbox_ops.settings.manage

### Responses

**200** – Inbox settings

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/inbox_ops/settings" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PATCH `/inbox_ops/settings`

Update tenant inbox configuration

Updates working language and/or active status

Requires features: inbox_ops.settings.manage

**Tags:** InboxOps

**Requires authentication.**

**Features:** inbox_ops.settings.manage

### Responses

**200** – Updated settings

Content-Type: `application/json`

**404** – Settings not found

Content-Type: `application/json`

### Example

```bash
curl -X PATCH "https://crmprod.erp.sobota.myopenmercato.com/inbox_ops/settings" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/inbox_ops/webhook/inbound`

Receive forwarded email from provider webhook

Public endpoint — validated by provider HMAC signature or Resend/Svix signature. Rate limited per tenant.

**Tags:** InboxOps

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Email received and queued for processing

Content-Type: `application/json`

**400** – Invalid payload or signature

Content-Type: `application/json`

**413** – Payload too large

Content-Type: `application/json`

**429** – Rate limit exceeded

Content-Type: `application/json`

**503** – Webhook secret not configured

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/inbox_ops/webhook/inbound" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## GET `/integrations`

List integrations

Returns a paginated collection of integrations.

Requires features: integrations.view

**Tags:** Integrations

**Requires authentication.**

**Features:** integrations.view

### Responses

**200** – Paginated integrations

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "title": "string",
      "category": null,
      "hub": null,
      "providerKey": null,
      "bundleId": null,
      "hasCredentials": true,
      "isEnabled": true,
      "apiVersion": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/integrations" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/integrations/{id}`

Get integration detail

Requires features: integrations.view

**Tags:** Integrations

**Requires authentication.**

**Features:** integrations.view

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/integrations/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/integrations/{id}/credentials`

Get or save integration credentials

Requires features: integrations.credentials.manage

**Tags:** Integrations

**Requires authentication.**

**Features:** integrations.credentials.manage

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/integrations/:id/credentials" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/integrations/{id}/credentials`

Get or save integration credentials

Requires features: integrations.credentials.manage

**Tags:** Integrations

**Requires authentication.**

**Features:** integrations.credentials.manage

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/integrations/:id/credentials" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/integrations/{id}/health`

Run health check for an integration

Requires features: integrations.manage

**Tags:** Integrations

**Requires authentication.**

**Features:** integrations.manage

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

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/integrations/:id/health" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/integrations/{id}/state`

Update integration state

Requires features: integrations.manage

**Tags:** Integrations

**Requires authentication.**

**Features:** integrations.manage

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/integrations/:id/state" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/integrations/{id}/version`

Change integration API version

Requires features: integrations.manage

**Tags:** Integrations

**Requires authentication.**

**Features:** integrations.manage

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/integrations/:id/version" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/integrations/logs`

List integration logs

Requires features: integrations.manage

**Tags:** Integrations

**Requires authentication.**

**Features:** integrations.manage

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/integrations/logs" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/messages`

List messages

Requires features: messages.view

**Tags:** Messages

**Requires authentication.**

**Features:** messages.view

### 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://crmprod.erp.sobota.myopenmercato.com/messages?folder=inbox&page=1&pageSize=20" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/messages`

Compose a message

Requires features: messages.compose

**Tags:** Messages

**Requires authentication.**

**Features:** messages.compose

### 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://crmprod.erp.sobota.myopenmercato.com/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

Requires features: messages.view

**Tags:** Messages

**Requires authentication.**

**Features:** messages.view

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

### Responses

**200** – Message deleted

Content-Type: `application/json`

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

**404** – Message not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/messages/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/messages/{id}`

Get message detail

Requires features: messages.view

**Tags:** Messages

**Requires authentication.**

**Features:** messages.view

### 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",
  "type": "string",
  "isDraft": true,
  "canEditDraft": 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
}
```

**404** – Message not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/messages/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PATCH `/messages/{id}`

Update draft message

Requires features: messages.compose

**Tags:** Messages

**Requires authentication.**

**Features:** messages.compose

### 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
}
```

**404** – Message not found

Content-Type: `application/json`

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

**409** – Only drafts can be edited

Content-Type: `application/json`

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

### Example

```bash
curl -X PATCH "https://crmprod.erp.sobota.myopenmercato.com/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

Requires features: messages.actions

**Tags:** Messages

**Requires authentication.**

**Features:** messages.actions

### 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"
}
```

**404** – Action not found

Content-Type: `application/json`

**409** – Action already taken

Content-Type: `application/json`

**410** – Action expired

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/messages/:id/actions/:actionId" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/messages/{id}/archive`

Unarchive message

Requires features: messages.view

**Tags:** Messages

**Requires authentication.**

**Features:** messages.view

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

### Responses

**200** – Message unarchived

Content-Type: `application/json`

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

**404** – Message not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/messages/:id/archive" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/messages/{id}/archive`

Archive message

Requires features: messages.view

**Tags:** Messages

**Requires authentication.**

**Features:** messages.view

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

### Responses

**200** – Message archived

Content-Type: `application/json`

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

**404** – Message not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/messages/:id/archive" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

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

Unlink attachments from draft message

Requires features: messages.attach_files

**Tags:** Messages

**Requires authentication.**

**Features:** messages.attach_files

### 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
}
```

**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://crmprod.erp.sobota.myopenmercato.com/messages/:id/attachments" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

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

List message attachments

Requires features: messages.view

**Tags:** Messages

**Requires authentication.**

**Features:** messages.view

### 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"
    }
  ]
}
```

**404** – Message not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/messages/:id/attachments" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/messages/{id}/attachments`

Link attachments to draft message

Requires features: messages.attach_files

**Tags:** Messages

**Requires authentication.**

**Features:** messages.attach_files

### 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
}
```

**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://crmprod.erp.sobota.myopenmercato.com/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

Requires features: messages.view

**Tags:** Messages

**Requires authentication.**

**Features:** messages.view

### 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
}
```

**404** – Message not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/messages/:id/confirmation" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/messages/{id}/conversation`

Delete conversation for current actor

Requires features: messages.view

**Tags:** Messages

**Requires authentication.**

**Features:** messages.view

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

### Responses

**200** – Conversation deleted

Content-Type: `application/json`

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

**404** – Message not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/messages/:id/conversation" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/messages/{id}/conversation/archive`

Archive conversation for current actor

Requires features: messages.view

**Tags:** Messages

**Requires authentication.**

**Features:** messages.view

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

### Responses

**200** – Conversation archived

Content-Type: `application/json`

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

**404** – Message not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/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

Requires features: messages.view

**Tags:** Messages

**Requires authentication.**

**Features:** messages.view

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

### Responses

**200** – Conversation marked unread

Content-Type: `application/json`

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

**404** – Message not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/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

Requires features: messages.compose

**Tags:** Messages

**Requires authentication.**

**Features:** messages.compose

### 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"
}
```

**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://crmprod.erp.sobota.myopenmercato.com/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

Requires features: messages.compose

**Tags:** Messages

**Requires authentication.**

**Features:** messages.compose

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

### Responses

**200** – Forward preview generated

Content-Type: `application/json`

```json
{
  "subject": "string",
  "body": "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://crmprod.erp.sobota.myopenmercato.com/messages/:id/forward-preview" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/messages/{id}/read`

Mark message as unread

Requires features: messages.view

**Tags:** Messages

**Requires authentication.**

**Features:** messages.view

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

### Responses

**200** – Message marked unread

Content-Type: `application/json`

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

**404** – Message not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/messages/:id/read" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/messages/{id}/read`

Mark message as read

Requires features: messages.view

**Tags:** Messages

**Requires authentication.**

**Features:** messages.view

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

### Responses

**200** – Message marked read

Content-Type: `application/json`

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

**404** – Message not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/messages/:id/read" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/messages/{id}/reply`

Reply to message

Requires features: messages.compose

**Tags:** Messages

**Requires authentication.**

**Features:** messages.compose

### 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"
}
```

**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://crmprod.erp.sobota.myopenmercato.com/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

Requires features: messages.compose

**Tags:** Messages

**Requires authentication.**

**Features:** messages.compose

### 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://crmprod.erp.sobota.myopenmercato.com/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://crmprod.erp.sobota.myopenmercato.com/messages/token/:token" \
  -H "Accept: application/json"
```

## GET `/messages/types`

List registered message types

Requires features: messages.view

**Tags:** Messages

**Requires authentication.**

**Features:** messages.view

### 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://crmprod.erp.sobota.myopenmercato.com/messages/types" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/messages/unread-count`

Get unread message count

Requires features: messages.view

**Tags:** Messages

**Requires authentication.**

**Features:** messages.view

### Responses

**200** – Unread count

Content-Type: `application/json`

```json
{
  "unreadCount": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/notifications?page=1&pageSize=20" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/notifications`

Create notification

Creates a notification for a user.

Requires features: notifications.create

**Tags:** Notifications

**Requires authentication.**

**Features:** notifications.create

### 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://crmprod.erp.sobota.myopenmercato.com/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://crmprod.erp.sobota.myopenmercato.com/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://crmprod.erp.sobota.myopenmercato.com/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://crmprod.erp.sobota.myopenmercato.com/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://crmprod.erp.sobota.myopenmercato.com/notifications/:id/restore" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/notifications/batch`

POST /notifications/batch

Requires features: notifications.create

**Tags:** Notifications

**Requires authentication.**

**Features:** notifications.create

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/notifications/batch" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/notifications/feature`

POST /notifications/feature

Requires features: notifications.create

**Tags:** Notifications

**Requires authentication.**

**Features:** notifications.create

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/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://crmprod.erp.sobota.myopenmercato.com/notifications/mark-all-read" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/notifications/role`

POST /notifications/role

Requires features: notifications.create

**Tags:** Notifications

**Requires authentication.**

**Features:** notifications.create

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/notifications/role" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/notifications/settings`

GET /notifications/settings

Requires features: notifications.manage

**Tags:** Notifications

**Requires authentication.**

**Features:** notifications.manage

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/notifications/settings" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/notifications/settings`

POST /notifications/settings

Requires features: notifications.manage

**Tags:** Notifications

**Requires authentication.**

**Features:** notifications.manage

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/notifications/settings" \
  -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://crmprod.erp.sobota.myopenmercato.com/notifications/unread-count" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/onboarding/demo-feedback`

Submit demo feedback

Sends a feedback/contact request from the demo environment to the admin and optionally to the user.

**Tags:** Demo

### Request Body

Content-Type: `application/json`

```json
{
  "email": "user@example.com",
  "message": "",
  "termsAccepted": true,
  "marketingConsent": false,
  "sendCopy": true
}
```

### Responses

**200** – Feedback sent successfully.

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/onboarding/demo-feedback" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"email\": \"user@example.com\",
  \"message\": \"\",
  \"termsAccepted\": true,
  \"marketingConsent\": false,
  \"sendCopy\": true
}"
```

## POST `/onboarding/onboarding`

POST /onboarding/onboarding

**Tags:** Onboarding

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/onboarding/onboarding" \
  -H "Accept: application/json"
```

## GET `/onboarding/onboarding/verify`

GET /onboarding/onboarding/verify

**Tags:** Onboarding

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/onboarding/onboarding/verify" \
  -H "Accept: application/json"
```

## POST `/payment_gateways/cancel`

Cancel payment

Requires features: payment_gateways.manage

**Tags:** PaymentGateways

**Requires authentication.**

**Features:** payment_gateways.manage

### Responses

**200** – Payment cancelled

Content-Type: `application/json`

**422** – Invalid payload

Content-Type: `application/json`

**502** – Gateway provider error

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/payment_gateways/cancel" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/payment_gateways/capture`

Capture payment

Requires features: payment_gateways.capture

**Tags:** PaymentGateways

**Requires authentication.**

**Features:** payment_gateways.capture

### Responses

**200** – Payment captured

Content-Type: `application/json`

**422** – Invalid payload

Content-Type: `application/json`

**502** – Gateway provider error

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/payment_gateways/capture" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/payment_gateways/providers`

List payment gateway descriptors

Requires features: payment_gateways.view

**Tags:** PaymentGateways

**Requires authentication.**

**Features:** payment_gateways.view

### Responses

**200** – List of safe payment gateway descriptors

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/payment_gateways/providers" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/payment_gateways/providers/{providerKey}`

Get payment gateway descriptor

Requires features: payment_gateways.view

**Tags:** PaymentGateways

**Requires authentication.**

**Features:** payment_gateways.view

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

### Responses

**200** – Provider descriptor

Content-Type: `application/json`

**404** – Provider descriptor not found

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/payment_gateways/providers/:providerKey" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/payment_gateways/refund`

Refund payment

Requires features: payment_gateways.refund

**Tags:** PaymentGateways

**Requires authentication.**

**Features:** payment_gateways.refund

### Responses

**200** – Payment refunded

Content-Type: `application/json`

**422** – Invalid payload

Content-Type: `application/json`

**502** – Gateway provider error

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/payment_gateways/refund" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/payment_gateways/sessions`

Create payment session

Requires features: payment_gateways.manage

**Tags:** PaymentGateways

**Requires authentication.**

**Features:** payment_gateways.manage

### Responses

**201** – Payment session created

Content-Type: `application/json`

**422** – Invalid payload or unknown provider

Content-Type: `application/json`

**502** – Gateway provider error

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/payment_gateways/sessions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/payment_gateways/status`

Get transaction status

Requires features: payment_gateways.view

**Tags:** PaymentGateways

**Requires authentication.**

**Features:** payment_gateways.view

### Responses

**200** – Transaction status

Content-Type: `application/json`

**404** – Transaction not found

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/payment_gateways/status" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/payment_gateways/transactions`

List payment transactions

Requires features: payment_gateways.view

**Tags:** PaymentGateways

**Requires authentication.**

**Features:** payment_gateways.view

### Responses

**200** – Payment transaction list

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/payment_gateways/transactions" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/payment_gateways/transactions/{id}`

Get payment transaction details

Requires features: payment_gateways.view

**Tags:** PaymentGateways

**Requires authentication.**

**Features:** payment_gateways.view

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

### Responses

**200** – Payment transaction details

Content-Type: `application/json`

**404** – Transaction not found

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/payment_gateways/transactions/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/payment_gateways/webhook/{provider}`

Process inbound webhook from payment provider

**Tags:** PaymentGateways

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

### Responses

**202** – Webhook accepted for async processing

Content-Type: `application/json`

**401** – Signature verification failed

Content-Type: `application/json`

**404** – Unknown provider

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/payment_gateways/webhook/:provider" \
  -H "Accept: application/json"
```

## GET `/perspectives/{tableId}`

Load perspectives for a table

Returns personal perspectives and available role defaults for the requested table identifier.

Requires features: perspectives.use

**Tags:** Perspectives

**Requires authentication.**

**Features:** perspectives.use

### 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
    }
  ],
  "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"
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: perspectives.use

**Tags:** Perspectives

**Requires authentication.**

**Features:** perspectives.use

### 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"
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: perspectives.use

**Tags:** Perspectives

**Requires authentication.**

**Features:** perspectives.use

### 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"
}
```

**404** – Perspective not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: perspectives.role_defaults

**Tags:** Perspectives

**Requires authentication.**

**Features:** perspectives.role_defaults

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| tableId | path | any | Required |
| roleId | path | any | Required |

### Responses

**200** – Role perspectives cleared.

Content-Type: `application/json`

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

**400** – Invalid identifiers supplied

Content-Type: `application/json`

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

**404** – Role not found in scope

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/perspectives/string/roles/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/planner/availability`

Delete availability rule

Deletes an availability rule by id.

**Tags:** Planner

**Requires authentication.**

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Availability rule deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/planner/availability" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/planner/availability`

List availability rules

Returns a paginated collection of availability rules scoped to the authenticated organization.

Requires features: planner.view

**Tags:** Planner

**Requires authentication.**

**Features:** planner.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| subjectType | query | any | Optional |
| subjectIds | 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 availability rules

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": null,
      "organization_id": null,
      "tenant_id": null,
      "subject_type": null,
      "subject_id": null,
      "timezone": null,
      "rrule": null,
      "exdates": null,
      "kind": null,
      "note": null,
      "unavailability_reason_entry_id": null,
      "unavailability_reason_value": null,
      "created_at": null,
      "updated_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/planner/availability?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/planner/availability`

Create availability rule

Creates an availability rule for the selected subject.

**Tags:** Planner

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "subjectType": "member",
  "subjectId": "00000000-0000-4000-8000-000000000000",
  "timezone": "string",
  "rrule": "string",
  "exdates": [],
  "kind": "availability",
  "note": null,
  "unavailabilityReasonEntryId": null,
  "unavailabilityReasonValue": null
}
```

### Responses

**201** – Availability rule created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/planner/availability" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"subjectType\": \"member\",
  \"subjectId\": \"00000000-0000-4000-8000-000000000000\",
  \"timezone\": \"string\",
  \"rrule\": \"string\",
  \"exdates\": [],
  \"kind\": \"availability\",
  \"note\": null,
  \"unavailabilityReasonEntryId\": null,
  \"unavailabilityReasonValue\": null
}"
```

## PUT `/planner/availability`

Update availability rule

Updates an availability rule by id.

**Tags:** Planner

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "note": null,
  "unavailabilityReasonEntryId": null,
  "unavailabilityReasonValue": null
}
```

### Responses

**200** – Availability rule updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/planner/availability" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"note\": null,
  \"unavailabilityReasonEntryId\": null,
  \"unavailabilityReasonValue\": null
}"
```

## POST `/planner/availability-date-specific`

Replace date-specific availability

Replaces date-specific availability rules for the subject in a single request.

**Tags:** Planner

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "subjectType": "member",
  "subjectId": "00000000-0000-4000-8000-000000000000",
  "timezone": "string",
  "windows": [],
  "isAvailable": true,
  "note": null,
  "unavailabilityReasonEntryId": null,
  "unavailabilityReasonValue": null
}
```

### Responses

**200** – Date-specific availability updated

Content-Type: `application/json`

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

**400** – Invalid payload

Content-Type: `application/json`

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

**403** – Forbidden

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/planner/availability-date-specific" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"subjectType\": \"member\",
  \"subjectId\": \"00000000-0000-4000-8000-000000000000\",
  \"timezone\": \"string\",
  \"windows\": [],
  \"isAvailable\": true,
  \"note\": null,
  \"unavailabilityReasonEntryId\": null,
  \"unavailabilityReasonValue\": null
}"
```

## DELETE `/planner/availability-rule-sets`

Delete availability rule set

Deletes an availability rule set by id.

Requires features: planner.manage_availability

**Tags:** Planner

**Requires authentication.**

**Features:** planner.manage_availability

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Availability rule set deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/planner/availability-rule-sets" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/planner/availability-rule-sets`

List availability rule sets

Returns a paginated collection of availability rule sets scoped to the authenticated organization.

Requires features: planner.view

**Tags:** Planner

**Requires authentication.**

**Features:** planner.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |
| search | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |

### Responses

**200** – Paginated availability rule sets

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": null,
      "organization_id": null,
      "tenant_id": null,
      "name": null,
      "description": null,
      "timezone": null,
      "created_at": null,
      "updated_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/planner/availability-rule-sets?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/planner/availability-rule-sets`

Create availability rule set

Creates a reusable availability rule set.

Requires features: planner.manage_availability

**Tags:** Planner

**Requires authentication.**

**Features:** planner.manage_availability

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "name": "string",
  "description": null,
  "timezone": "string"
}
```

### Responses

**201** – Availability rule set created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/planner/availability-rule-sets" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"name\": \"string\",
  \"description\": null,
  \"timezone\": \"string\"
}"
```

## PUT `/planner/availability-rule-sets`

Update availability rule set

Updates an availability rule set by id.

Requires features: planner.manage_availability

**Tags:** Planner

**Requires authentication.**

**Features:** planner.manage_availability

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Availability rule set updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/planner/availability-rule-sets" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"description\": null
}"
```

## POST `/planner/availability-weekly`

Replace weekly availability

Replaces weekly availability rules for the subject in a single request.

**Tags:** Planner

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "subjectType": "member",
  "subjectId": "00000000-0000-4000-8000-000000000000",
  "timezone": "string",
  "windows": []
}
```

### Responses

**200** – Weekly availability updated

Content-Type: `application/json`

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

**400** – Invalid payload

Content-Type: `application/json`

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

**403** – Forbidden

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/planner/availability-weekly" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"subjectType\": \"member\",
  \"subjectId\": \"00000000-0000-4000-8000-000000000000\",
  \"timezone\": \"string\",
  \"windows\": []
}"
```

## GET `/progress/active`

GET /progress/active

**Tags:** Progress

**Requires authentication.**

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/progress/active" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/progress/jobs`

List progressjobs

Returns a paginated collection of progressjobs scoped to the authenticated tenant.

**Tags:** Progress

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| status | query | any | Optional |
| jobType | query | any | Optional |
| parentJobId | query | any | Optional |
| includeCompleted | query | any | Optional |
| completedSince | query | any | Optional |
| 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 progressjobs

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "jobType": "string",
      "name": "string",
      "description": null,
      "status": "string",
      "progressPercent": 1,
      "processedCount": 1,
      "totalCount": null,
      "etaSeconds": null,
      "cancellable": true,
      "startedAt": null,
      "finishedAt": null,
      "errorMessage": null,
      "createdAt": null,
      "tenantId": "00000000-0000-4000-8000-000000000000",
      "organizationId": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/progress/jobs?page=1&pageSize=20" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/progress/jobs`

Create progressjob

Creates a new progress job for tracking a long-running operation.

Requires features: progress.create

**Tags:** Progress

**Requires authentication.**

**Features:** progress.create

### Request Body

Content-Type: `application/json`

```json
{
  "jobType": "string",
  "name": "string",
  "cancellable": false
}
```

### Responses

**201** – ProgressJob created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/progress/jobs" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"jobType\": \"string\",
  \"name\": \"string\",
  \"cancellable\": false
}"
```

## DELETE `/progress/jobs/{id}`

DELETE /progress/jobs/{id}

Requires features: progress.cancel

**Tags:** Progress

**Requires authentication.**

**Features:** progress.cancel

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

### Responses

**204** – Success

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/progress/jobs/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/progress/jobs/{id}`

GET /progress/jobs/{id}

**Tags:** Progress

**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://crmprod.erp.sobota.myopenmercato.com/progress/jobs/:id" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/progress/jobs/{id}`

PUT /progress/jobs/{id}

Requires features: progress.update

**Tags:** Progress

**Requires authentication.**

**Features:** progress.update

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

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/progress/jobs/:id" \
  -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.

Requires features: query_index.purge

**Tags:** Query Index

**Requires authentication.**

**Features:** query_index.purge

### 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"
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: query_index.reindex

**Tags:** Query Index

**Requires authentication.**

**Features:** query_index.reindex

### 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"
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: query_index.status.view

**Tags:** Query Index

**Requires authentication.**

**Features:** query_index.status.view

### Responses

**200** – Current query index status.

Content-Type: `application/json`

```json
{
  "items": [
    {
      "entityId": "string",
      "label": "string",
      "baseCount": null,
      "indexCount": null,
      "vectorCount": null,
      "ok": true,
      "job": {
        "status": "idle",
        "startedAt": null,
        "finishedAt": null,
        "heartbeatAt": null,
        "processedCount": null,
        "totalCount": null,
        "scope": 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"
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/query_index/status" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/resources/activities`

Delete resourceactivity

Deletes a resource activity.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – ResourceActivity deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/resources/activities" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/resources/activities`

List resourceactivitys

Returns a paginated collection of resourceactivitys scoped to the authenticated organization.

Requires features: resources.view

**Tags:** Resources

**Requires authentication.**

**Features:** resources.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| entityId | 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 resourceactivitys

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "resource_id": null,
      "activity_type": null,
      "subject": null,
      "body": null,
      "occurred_at": 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://crmprod.erp.sobota.myopenmercato.com/resources/activities?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/resources/activities`

Create resourceactivity

Adds an activity to a resource timeline.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "entityId": "00000000-0000-4000-8000-000000000000",
  "activityType": "string",
  "appearanceIcon": null,
  "appearanceColor": null
}
```

### Responses

**201** – ResourceActivity created

Content-Type: `application/json`

```json
{
  "id": null,
  "authorUserId": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/resources/activities" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"entityId\": \"00000000-0000-4000-8000-000000000000\",
  \"activityType\": \"string\",
  \"appearanceIcon\": null,
  \"appearanceColor\": null
}"
```

## PUT `/resources/activities`

Update resourceactivity

Updates a resource activity.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – ResourceActivity updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/resources/activities" \
  -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 `/resources/comments`

Delete resourcecomment

Deletes a resource note.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – ResourceComment deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/resources/comments" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/resources/comments`

List resourcecomments

Returns a paginated collection of resourcecomments scoped to the authenticated organization.

Requires features: resources.view

**Tags:** Resources

**Requires authentication.**

**Features:** resources.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| entityId | 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 resourcecomments

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "resource_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://crmprod.erp.sobota.myopenmercato.com/resources/comments?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/resources/comments`

Create resourcecomment

Adds a note to a resource timeline.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "entityId": "00000000-0000-4000-8000-000000000000",
  "body": "string",
  "appearanceIcon": null,
  "appearanceColor": null
}
```

### Responses

**201** – ResourceComment created

Content-Type: `application/json`

```json
{
  "id": null,
  "authorUserId": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/resources/comments" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"entityId\": \"00000000-0000-4000-8000-000000000000\",
  \"body\": \"string\",
  \"appearanceIcon\": null,
  \"appearanceColor\": null
}"
```

## PUT `/resources/comments`

Update resourcecomment

Updates a resource note.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – ResourceComment updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/resources/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 `/resources/resource-types`

Delete resource type

Deletes a resource type by id.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Resource type deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/resources/resource-types" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/resources/resource-types`

List resource types

Returns a paginated collection of resource types scoped to the authenticated organization.

Requires features: resources.view

**Tags:** Resources

**Requires authentication.**

**Features:** resources.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |

### Responses

**200** – Paginated resource types

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": null,
      "organization_id": null,
      "tenant_id": null,
      "name": null,
      "description": null,
      "appearance_icon": null,
      "appearance_color": null,
      "created_at": null,
      "updated_at": null,
      "resourceCount": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/resources/resource-types?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/resources/resource-types`

Create resource type

Creates a resource type for resources resources.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "name": "string",
  "description": null,
  "appearanceIcon": null,
  "appearanceColor": null
}
```

### Responses

**201** – Resource type created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/resources/resource-types" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"name\": \"string\",
  \"description\": null,
  \"appearanceIcon\": null,
  \"appearanceColor\": null
}"
```

## PUT `/resources/resource-types`

Update resource type

Updates a resource type by id.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "description": null,
  "appearanceIcon": null,
  "appearanceColor": null
}
```

### Responses

**200** – Resource type updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/resources/resource-types" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"description\": null,
  \"appearanceIcon\": null,
  \"appearanceColor\": null
}"
```

## DELETE `/resources/resources`

Delete resource

Deletes a resource by id.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Resource deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/resources/resources" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/resources/resources`

List resources

Returns a paginated collection of resources scoped to the authenticated organization.

Requires features: resources.view

**Tags:** Resources

**Requires authentication.**

**Features:** resources.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |
| resourceTypeId | query | any | Optional |
| isActive | query | any | Optional |
| tagIds | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |

### Responses

**200** – Paginated resources

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": null,
      "organization_id": null,
      "tenant_id": null,
      "name": null,
      "description": null,
      "resource_type_id": null,
      "capacity": null,
      "capacity_unit_value": null,
      "capacity_unit_name": null,
      "capacity_unit_color": null,
      "capacity_unit_icon": null,
      "appearance_icon": null,
      "appearance_color": null,
      "is_active": null,
      "availability_rule_set_id": null,
      "created_at": null,
      "updated_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/resources/resources?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/resources/resources`

Create resource

Creates a resource scoped to the selected organization.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "name": "string",
  "description": null,
  "resourceTypeId": null,
  "capacity": null,
  "capacityUnitValue": null,
  "appearanceIcon": null,
  "appearanceColor": null,
  "availabilityRuleSetId": null
}
```

### Responses

**201** – Resource created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/resources/resources" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"name\": \"string\",
  \"description\": null,
  \"resourceTypeId\": null,
  \"capacity\": null,
  \"capacityUnitValue\": null,
  \"appearanceIcon\": null,
  \"appearanceColor\": null,
  \"availabilityRuleSetId\": null
}"
```

## PUT `/resources/resources`

Update resource

Updates a resource by id.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "description": null,
  "resourceTypeId": null,
  "capacity": null,
  "capacityUnitValue": null,
  "appearanceIcon": null,
  "appearanceColor": null,
  "availabilityRuleSetId": null
}
```

### Responses

**200** – Resource updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/resources/resources" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"description\": null,
  \"resourceTypeId\": null,
  \"capacity\": null,
  \"capacityUnitValue\": null,
  \"appearanceIcon\": null,
  \"appearanceColor\": null,
  \"availabilityRuleSetId\": null
}"
```

## POST `/resources/resources/tags/assign`

Assign resource tag

Assigns a tag to a resources resource.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tagId": "00000000-0000-4000-8000-000000000000",
  "resourceId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**201** – Tag assignment created

Content-Type: `application/json`

```json
{
  "id": null
}
```

**400** – Invalid payload

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/resources/resources/tags/assign" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tagId\": \"00000000-0000-4000-8000-000000000000\",
  \"resourceId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## POST `/resources/resources/tags/unassign`

Unassign resource tag

Removes a tag from a resources resource.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tagId": "00000000-0000-4000-8000-000000000000",
  "resourceId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Tag assignment removed

Content-Type: `application/json`

```json
{
  "id": null
}
```

**400** – Invalid payload

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/resources/resources/tags/unassign" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tagId\": \"00000000-0000-4000-8000-000000000000\",
  \"resourceId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## DELETE `/resources/tags`

Delete resource tag

Deletes a resource tag by id.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Resource tag deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/resources/tags" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/resources/tags`

List resource tags

Returns a paginated collection of resource tags scoped to the authenticated organization.

Requires features: resources.view

**Tags:** Resources

**Requires authentication.**

**Features:** resources.view

### 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 resource tags

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": null,
      "slug": null,
      "label": null,
      "color": null,
      "description": null,
      "organization_id": null,
      "tenant_id": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/resources/tags?page=1&pageSize=100" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/resources/tags`

Create resource tag

Creates a tag for resources resources and services.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "label": "string",
  "color": null,
  "description": null
}
```

### Responses

**201** – Resource tag created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/resources/tags" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"label\": \"string\",
  \"color\": null,
  \"description\": null
}"
```

## PUT `/resources/tags`

Update resource tag

Updates a resource tag by id.

Requires features: resources.manage_resources

**Tags:** Resources

**Requires authentication.**

**Features:** resources.manage_resources

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Resource tag updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/resources/tags" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"color\": null,
  \"description\": null
}"
```

## DELETE `/sales/adjustment-kinds`

Delete sales adjustment kind

Deletes an adjustment kind.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Sales adjustment kind deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/sales/adjustment-kinds" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## GET `/sales/adjustment-kinds`

List sales adjustment kinds

Returns a paginated collection of sales adjustment kinds that belong to the current organization.

Requires features: sales.orders.view

**Tags:** Sales

**Requires authentication.**

**Features:** sales.orders.view

### 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 sales adjustment kinds

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "value": "string",
      "label": null,
      "color": null,
      "icon": null,
      "organizationId": null,
      "tenantId": null,
      "createdAt": "string",
      "updatedAt": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sales/adjustment-kinds?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/sales/adjustment-kinds`

Create sales adjustment kind

Creates an adjustment kind.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**201** – Sales adjustment kind created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/sales/adjustment-kinds" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## PUT `/sales/adjustment-kinds`

Update sales adjustment kind

Updates an adjustment kind.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Sales adjustment kind updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/sales/adjustment-kinds" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## DELETE `/sales/channels`

Delete sales channel

Deletes a sales channel identified by id.

Requires features: sales.channels.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.channels.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Sales channel deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/sales/channels" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/sales/channels`

List sales channels

Manage sales channels to segment orders and pricing across marketplaces or stores.

Requires features: sales.channels.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.channels.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| id | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |
| isActive | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| withDeleted | query | any | Optional |

### Responses

**200** – Paginated sales channels

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "code": null,
      "description": null,
      "statusEntryId": null,
      "isActive": true,
      "organizationId": null,
      "tenantId": null,
      "createdAt": "string",
      "updatedAt": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sales/channels?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/sales/channels`

Create sales channel

Creates a new sales channel.

Requires features: sales.channels.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.channels.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "name": "string",
  "code": "string"
}
```

### Responses

**201** – Sales channel created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/sales/channels" \
  -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\",
  \"code\": \"string\"
}"
```

## PUT `/sales/channels`

Update sales channel

Updates an existing sales channel by id.

Requires features: sales.channels.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.channels.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Sales channel updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/sales/channels" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"code\": \"string\"
}"
```

## GET `/sales/dashboard/widgets/new-orders`

Fetch recently created sales orders

Fetches recently created sales orders for the dashboard widget with a configurable date period.

Requires features: dashboards.view, sales.widgets.new-orders

**Tags:** Sales

**Requires authentication.**

**Features:** dashboards.view, sales.widgets.new-orders

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| limit | query | any | Optional |
| datePeriod | query | any | Optional |
| customFrom | query | any | Optional |
| customTo | query | any | Optional |
| tenantId | query | any | Optional |
| organizationId | query | any | Optional |

### Responses

**200** – List of recent orders

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "orderNumber": "string",
      "status": null,
      "fulfillmentStatus": null,
      "paymentStatus": null,
      "customerName": null,
      "customerEntityId": null,
      "netAmount": "string",
      "grossAmount": "string",
      "currency": null,
      "createdAt": "string"
    }
  ],
  "total": 1,
  "dateRange": {
    "from": "string",
    "to": "string"
  }
}
```

**400** – Invalid query parameters

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://crmprod.erp.sobota.myopenmercato.com/sales/dashboard/widgets/new-orders?limit=5&datePeriod=last24h" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/sales/dashboard/widgets/new-quotes`

Fetch recently created sales quotes

Fetches recently created sales quotes for the dashboard widget with a configurable date period.

Requires features: dashboards.view, sales.widgets.new-quotes

**Tags:** Sales

**Requires authentication.**

**Features:** dashboards.view, sales.widgets.new-quotes

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| limit | query | any | Optional |
| datePeriod | query | any | Optional |
| customFrom | query | any | Optional |
| customTo | query | any | Optional |
| tenantId | query | any | Optional |
| organizationId | query | any | Optional |

### Responses

**200** – List of recent quotes

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "quoteNumber": "string",
      "status": null,
      "customerName": null,
      "customerEntityId": null,
      "validFrom": null,
      "validUntil": null,
      "netAmount": "string",
      "grossAmount": "string",
      "currency": null,
      "createdAt": "string",
      "convertedOrderId": null
    }
  ],
  "total": 1,
  "dateRange": {
    "from": "string",
    "to": "string"
  }
}
```

**400** – Invalid query parameters

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://crmprod.erp.sobota.myopenmercato.com/sales/dashboard/widgets/new-quotes?limit=5&datePeriod=last24h" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/sales/delivery-windows`

Delete delivery window

Deletes a delivery window identified by id.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Delivery window deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/sales/delivery-windows" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/sales/delivery-windows`

List delivery windows

Define delivery windows to communicate lead times and cut-off rules for sales orders.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| isActive | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| withDeleted | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated delivery windows

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "code": null,
      "description": null,
      "leadTimeDays": null,
      "cutoffTime": null,
      "timezone": null,
      "isActive": true,
      "metadata": null,
      "organizationId": null,
      "tenantId": null,
      "createdAt": "string",
      "updatedAt": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sales/delivery-windows?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/sales/delivery-windows`

Create delivery window

Creates a new delivery window.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "name": "string",
  "code": "string"
}
```

### Responses

**201** – Delivery window created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/sales/delivery-windows" \
  -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\",
  \"code\": \"string\"
}"
```

## PUT `/sales/delivery-windows`

Update delivery window

Updates an existing delivery window by id.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Delivery window updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/sales/delivery-windows" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## DELETE `/sales/document-addresses`

Delete document address

Deletes a sales document address.

**Tags:** Sales

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "documentId": "00000000-0000-4000-8000-000000000000",
  "documentKind": "order"
}
```

### Responses

**200** – Document address deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/sales/document-addresses" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"documentId\": \"00000000-0000-4000-8000-000000000000\",
  \"documentKind\": \"order\"
}"
```

## GET `/sales/document-addresses`

List document addresss

Returns a paginated collection of document addresss that belong to the current organization.

**Tags:** Sales

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| documentId | query | any | Required |
| documentKind | 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 document addresss

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "document_id": "00000000-0000-4000-8000-000000000000",
      "document_kind": "order",
      "customer_address_id": null,
      "name": null,
      "purpose": null,
      "company_name": null,
      "address_line1": "string",
      "address_line2": null,
      "building_number": null,
      "flat_number": null,
      "city": null,
      "region": null,
      "postal_code": null,
      "country": null,
      "latitude": null,
      "longitude": null,
      "created_at": "string",
      "updated_at": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sales/document-addresses?page=1&pageSize=50&documentId=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/sales/document-addresses`

Create document address

Creates a sales document address linked to an order or quote.

**Tags:** Sales

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "documentId": "00000000-0000-4000-8000-000000000000",
  "documentKind": "order",
  "name": null,
  "purpose": null,
  "companyName": null,
  "addressLine1": "string",
  "addressLine2": null,
  "city": null,
  "region": null,
  "postalCode": null,
  "country": null,
  "buildingNumber": null,
  "flatNumber": null,
  "latitude": null,
  "longitude": null
}
```

### Responses

**201** – Document address created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/sales/document-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\",
  \"documentId\": \"00000000-0000-4000-8000-000000000000\",
  \"documentKind\": \"order\",
  \"name\": null,
  \"purpose\": null,
  \"companyName\": null,
  \"addressLine1\": \"string\",
  \"addressLine2\": null,
  \"city\": null,
  \"region\": null,
  \"postalCode\": null,
  \"country\": null,
  \"buildingNumber\": null,
  \"flatNumber\": null,
  \"latitude\": null,
  \"longitude\": null
}"
```

## PUT `/sales/document-addresses`

Update document address

Updates a sales document address.

**Tags:** Sales

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "id": "00000000-0000-4000-8000-000000000000",
  "documentId": "00000000-0000-4000-8000-000000000000",
  "documentKind": "order",
  "name": null,
  "purpose": null,
  "companyName": null,
  "addressLine1": "string",
  "addressLine2": null,
  "city": null,
  "region": null,
  "postalCode": null,
  "country": null,
  "buildingNumber": null,
  "flatNumber": null,
  "latitude": null,
  "longitude": null
}
```

### Responses

**200** – Document address updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/sales/document-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\",
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"documentId\": \"00000000-0000-4000-8000-000000000000\",
  \"documentKind\": \"order\",
  \"name\": null,
  \"purpose\": null,
  \"companyName\": null,
  \"addressLine1\": \"string\",
  \"addressLine2\": null,
  \"city\": null,
  \"region\": null,
  \"postalCode\": null,
  \"country\": null,
  \"buildingNumber\": null,
  \"flatNumber\": null,
  \"latitude\": null,
  \"longitude\": null
}"
```

## GET `/sales/document-history`

List history entries for an order or quote

**Tags:** Sales

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| kind | query | any | Required |
| id | query | any | Required |
| limit | query | any | Optional |
| before | query | any | Optional |
| after | query | any | Optional |
| types | query | any | Optional |

### Responses

**200** – History entries

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "occurredAt": "string",
      "kind": "status",
      "action": "string",
      "actor": {
        "id": null,
        "label": "string"
      },
      "source": "action_log"
    }
  ]
}
```

**400** – Invalid query

Content-Type: `application/json`

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

**404** – Document not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sales/document-history?kind=order&id=00000000-0000-4000-8000-000000000000&limit=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/sales/document-numbers`

Generate next number

Generates the next sales order or quote number using configured formatting rules.

**Tags:** Sales

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "kind": "order"
}
```

### Responses

**200** – Generated number

Content-Type: `application/json`

```json
{
  "number": "string",
  "format": "string",
  "sequence": 1
}
```

**400** – Invalid input or scope missing

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/sales/document-numbers" \
  -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\",
  \"kind\": \"order\"
}"
```

## DELETE `/sales/notes`

Delete sales note

Deletes a sales note.

**Tags:** Sales

**Requires authentication.**

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Sales note deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/sales/notes" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/sales/notes`

List sales notes

Returns a paginated collection of sales notes that belong to the current organization.

**Tags:** Sales

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| contextType | query | any | Optional |
| contextId | query | any | Optional |
| orderId | query | any | Optional |
| quoteId | 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 sales notes

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "context_type": "order",
      "context_id": "00000000-0000-4000-8000-000000000000",
      "order_id": null,
      "quote_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,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sales/notes?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/sales/notes`

Create sales note

Creates a note attached to a sales document.

**Tags:** Sales

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "contextType": "order",
  "contextId": "00000000-0000-4000-8000-000000000000",
  "body": "string",
  "appearanceIcon": null,
  "appearanceColor": null
}
```

### Responses

**201** – Sales note created

Content-Type: `application/json`

```json
{
  "id": null,
  "authorUserId": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/sales/notes" \
  -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\",
  \"contextType\": \"order\",
  \"contextId\": \"00000000-0000-4000-8000-000000000000\",
  \"body\": \"string\",
  \"appearanceIcon\": null,
  \"appearanceColor\": null
}"
```

## PUT `/sales/notes`

Update sales note

Updates a sales note.

**Tags:** Sales

**Requires authentication.**

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Sales note updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/sales/notes" \
  -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 `/sales/order-adjustments`

Delete order adjustment

Deletes an order adjustment and recalculates totals.

**Tags:** Sales

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Order adjustment deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/sales/order-adjustments" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"orderId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/sales/order-adjustments`

List order adjustments

Returns a paginated collection of order adjustments that belong to the current organization.

**Tags:** Sales

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| orderId | 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 order adjustments

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "order_id": "00000000-0000-4000-8000-000000000000",
      "order_line_id": null,
      "scope": "string",
      "kind": "string",
      "code": null,
      "label": null,
      "calculator_key": null,
      "promotion_id": null,
      "rate": 1,
      "amount_net": 1,
      "amount_gross": 1,
      "currency_code": null,
      "metadata": null,
      "position": 1,
      "created_at": "string",
      "updated_at": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sales/order-adjustments?page=1&pageSize=50" \
  -H "Accept: application/json"
```

## POST `/sales/order-adjustments`

Create order adjustment

Creates an order adjustment and recalculates totals.

**Tags:** Sales

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "orderId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**201** – Order adjustment created

Content-Type: `application/json`

```json
{
  "id": null,
  "orderId": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/sales/order-adjustments" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"orderId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## PUT `/sales/order-adjustments`

Update order adjustment

Updates an order adjustment and recalculates totals.

**Tags:** Sales

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "orderId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Order adjustment updated

Content-Type: `application/json`

```json
{
  "id": null,
  "orderId": null
}
```

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/sales/order-adjustments" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"orderId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## DELETE `/sales/order-line-statuses`

Delete order line status

Deletes a order line status identified by id.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Order line status deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/sales/order-line-statuses" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/sales/order-line-statuses`

List order line statuses

Manage custom order line statuses available for sales documents.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### 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 order line statuses

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "value": "string",
      "label": null,
      "color": null,
      "icon": null,
      "organizationId": null,
      "tenantId": null,
      "createdAt": "string",
      "updatedAt": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sales/order-line-statuses?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/sales/order-line-statuses`

Create order line status

Creates a new order line status.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "value": "string",
  "color": null,
  "icon": null
}
```

### Responses

**201** – Order line status created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/sales/order-line-statuses" \
  -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\",
  \"value\": \"string\",
  \"color\": null,
  \"icon\": null
}"
```

## PUT `/sales/order-line-statuses`

Update order line status

Updates an existing order line status by id.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "color": null,
  "icon": null,
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Order line status updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/sales/order-line-statuses" \
  -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\",
  \"color\": null,
  \"icon\": null,
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## DELETE `/sales/order-lines`

Delete order line

Deletes an order line and recalculates totals.

**Tags:** Sales

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Order line deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/sales/order-lines" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"orderId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/sales/order-lines`

List order lines

Returns a paginated collection of order lines that belong to the current organization.

**Tags:** Sales

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| id | query | any | Optional |
| orderId | 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 order lines

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "order_id": "00000000-0000-4000-8000-000000000000",
      "line_number": 1,
      "kind": "string",
      "status_entry_id": null,
      "status": null,
      "product_id": null,
      "product_variant_id": null,
      "catalog_snapshot": null,
      "name": null,
      "description": null,
      "comment": null,
      "quantity": 1,
      "quantity_unit": null,
      "normalized_quantity": 1,
      "normalized_unit": null,
      "uom_snapshot": null,
      "currency_code": "string",
      "unit_price_net": 1,
      "unit_price_gross": 1,
      "discount_amount": 1,
      "discount_percent": 1,
      "tax_rate": 1,
      "tax_amount": 1,
      "total_net_amount": 1,
      "total_gross_amount": 1,
      "configuration": null,
      "promotion_code": null,
      "promotion_snapshot": null,
      "metadata": null,
      "custom_field_set_id": null,
      "created_at": "string",
      "updated_at": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sales/order-lines?page=1&pageSize=50" \
  -H "Accept: application/json"
```

## POST `/sales/order-lines`

Create order line

Creates an order line and recalculates totals.

**Tags:** Sales

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "orderId": "00000000-0000-4000-8000-000000000000",
  "currencyCode": "string",
  "uomSnapshot": null,
  "quantity": 1,
  "normalizedUnit": null
}
```

### Responses

**201** – Order line created

Content-Type: `application/json`

```json
{
  "id": null,
  "orderId": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/sales/order-lines" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"orderId\": \"00000000-0000-4000-8000-000000000000\",
  \"currencyCode\": \"string\",
  \"uomSnapshot\": null,
  \"quantity\": 1,
  \"normalizedUnit\": null
}"
```

## PUT `/sales/order-lines`

Update order line

Updates an order line and recalculates totals.

**Tags:** Sales

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "orderId": "00000000-0000-4000-8000-000000000000",
  "currencyCode": "string",
  "uomSnapshot": null,
  "quantity": 1,
  "normalizedUnit": null
}
```

### Responses

**200** – Order line updated

Content-Type: `application/json`

```json
{
  "id": null,
  "orderId": null
}
```

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/sales/order-lines" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"orderId\": \"00000000-0000-4000-8000-000000000000\",
  \"currencyCode\": \"string\",
  \"uomSnapshot\": null,
  \"quantity\": 1,
  \"normalizedUnit\": null
}"
```

## DELETE `/sales/order-statuses`

Delete order status

Deletes a order status identified by id.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Order status deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/sales/order-statuses" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/sales/order-statuses`

List order statuses

Manage the lifecycle states available for sales orders.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### 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 order statuses

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "value": "string",
      "label": null,
      "color": null,
      "icon": null,
      "organizationId": null,
      "tenantId": null,
      "createdAt": "string",
      "updatedAt": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sales/order-statuses?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/sales/order-statuses`

Create order status

Creates a new order status.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "value": "string",
  "color": null,
  "icon": null
}
```

### Responses

**201** – Order status created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/sales/order-statuses" \
  -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\",
  \"value\": \"string\",
  \"color\": null,
  \"icon\": null
}"
```

## PUT `/sales/order-statuses`

Update order status

Updates an existing order status by id.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "color": null,
  "icon": null,
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Order status updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/sales/order-statuses" \
  -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\",
  \"color\": null,
  \"icon\": null,
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## DELETE `/sales/orders`

Delete order

Deletes a sales order.

Requires features: sales.orders.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.orders.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Order deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/sales/orders" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/sales/orders`

List orders

Returns a paginated collection of orders that belong to the current organization.

Requires features: sales.orders.view

**Tags:** Sales

**Requires authentication.**

**Features:** sales.orders.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| id | query | any | Optional |
| customerId | query | any | Optional |
| channelId | query | any | Optional |
| lineItemCountMin | query | any | Optional |
| lineItemCountMax | query | any | Optional |
| totalNetMin | query | any | Optional |
| totalNetMax | query | any | Optional |
| totalGrossMin | query | any | Optional |
| totalGrossMax | query | any | Optional |
| dateFrom | query | any | Optional |
| dateTo | query | any | Optional |
| tagIds | query | any | Optional |
| tagIdsEmpty | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| withDeleted | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated orders

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "orderNumber": null,
      "status": null,
      "statusEntryId": null,
      "customerEntityId": null,
      "customerContactId": null,
      "billingAddressId": null,
      "shippingAddressId": null,
      "customerReference": null,
      "externalReference": null,
      "comment": null,
      "placedAt": null,
      "expectedDeliveryAt": null,
      "customerSnapshot": null,
      "billingAddressSnapshot": null,
      "shippingAddressSnapshot": null,
      "shippingMethodId": null,
      "shippingMethodCode": null,
      "shippingMethodSnapshot": null,
      "paymentMethodId": null,
      "paymentMethodCode": null,
      "paymentMethodSnapshot": null,
      "currencyCode": null,
      "channelId": null,
      "organizationId": null,
      "tenantId": null,
      "validFrom": null,
      "validUntil": null,
      "lineItemCount": null,
      "subtotalNetAmount": null,
      "subtotalGrossAmount": null,
      "discountTotalAmount": null,
      "taxTotalAmount": null,
      "shippingNetAmount": null,
      "shippingGrossAmount": null,
      "surchargeTotalAmount": null,
      "grandTotalNetAmount": null,
      "grandTotalGrossAmount": null,
      "paidTotalAmount": null,
      "refundedTotalAmount": null,
      "outstandingAmount": null,
      "createdAt": "string",
      "updatedAt": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sales/orders?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/sales/orders`

Create order

Creates a new sales order.

Requires features: sales.orders.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.orders.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "currencyCode": "string"
}
```

### Responses

**201** – Order created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/sales/orders" \
  -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\",
  \"currencyCode\": \"string\"
}"
```

## PUT `/sales/orders`

Order management

Requires features: sales.orders.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.orders.manage

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/sales/orders" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/sales/payment-methods`

Delete payment method

Deletes a payment method identified by id.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Payment method deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/sales/payment-methods" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/sales/payment-methods`

List payment methods

Configure payment options that can be assigned to sales orders and invoices.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| isActive | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| withDeleted | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated payment methods

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "code": "string",
      "description": null,
      "providerKey": null,
      "terms": null,
      "isActive": true,
      "metadata": null,
      "providerSettings": null,
      "organizationId": null,
      "tenantId": null,
      "createdAt": "string",
      "updatedAt": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sales/payment-methods?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/sales/payment-methods`

Create payment method

Creates a new payment method.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "name": "string",
  "code": "string"
}
```

### Responses

**201** – Payment method created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/sales/payment-methods" \
  -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\",
  \"code\": \"string\"
}"
```

## PUT `/sales/payment-methods`

Update payment method

Updates an existing payment method by id.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Payment method updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/sales/payment-methods" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## DELETE `/sales/payment-statuses`

Delete payment status

Deletes a payment status identified by id.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Payment status deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/sales/payment-statuses" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/sales/payment-statuses`

List payment statuses

Manage the lifecycle states available for payments.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### 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 payment statuses

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "value": "string",
      "label": null,
      "color": null,
      "icon": null,
      "organizationId": null,
      "tenantId": null,
      "createdAt": "string",
      "updatedAt": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sales/payment-statuses?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/sales/payment-statuses`

Create payment status

Creates a new payment status.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "value": "string",
  "color": null,
  "icon": null
}
```

### Responses

**201** – Payment status created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/sales/payment-statuses" \
  -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\",
  \"value\": \"string\",
  \"color\": null,
  \"icon\": null
}"
```

## PUT `/sales/payment-statuses`

Update payment status

Updates an existing payment status by id.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "color": null,
  "icon": null,
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Payment status updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/sales/payment-statuses" \
  -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\",
  \"color\": null,
  \"icon\": null,
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## DELETE `/sales/payments`

Delete payment

Deletes a payment.

Requires features: sales.payments.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.payments.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Payment deleted

Content-Type: `application/json`

```json
{
  "id": null,
  "orderTotals": null
}
```

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/sales/payments" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/sales/payments`

List payments

Returns a paginated collection of payments that belong to the current organization.

Requires features: sales.orders.view

**Tags:** Sales

**Requires authentication.**

**Features:** sales.orders.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| orderId | query | any | Optional |
| paymentMethodId | 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 payments

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "order_id": null,
      "payment_method_id": null,
      "payment_method_name": null,
      "payment_method_code": null,
      "payment_reference": null,
      "status_entry_id": null,
      "status": null,
      "status_label": null,
      "amount": 1,
      "currency_code": "string",
      "captured_amount": null,
      "refunded_amount": null,
      "received_at": null,
      "captured_at": null,
      "custom_field_set_id": null,
      "customFieldSetId": null,
      "custom_values": null,
      "customValues": null,
      "custom_fields": null,
      "customFields": null,
      "metadata": null,
      "created_at": "string",
      "updated_at": null
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sales/payments?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/sales/payments`

Create payment

Creates a payment for a sales order.

Requires features: sales.payments.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.payments.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "amount": 1,
  "currencyCode": "string"
}
```

### Responses

**201** – Payment created

Content-Type: `application/json`

```json
{
  "id": null,
  "orderTotals": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/sales/payments" \
  -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\",
  \"amount\": 1,
  \"currencyCode\": \"string\"
}"
```

## PUT `/sales/payments`

Update payment

Updates a payment.

Requires features: sales.payments.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.payments.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Payment updated

Content-Type: `application/json`

```json
{
  "id": null,
  "orderTotals": null
}
```

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/sales/payments" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/sales/price-kinds`

List price kinds

Lists available price kinds that can be used when pricing sales channels and offers.

Requires features: sales.channels.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.channels.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| isActive | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated price kinds

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "code": "string",
      "title": "string",
      "currency_code": null,
      "display_mode": "string",
      "is_active": true
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sales/price-kinds?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/sales/quote-adjustments`

Delete quote adjustment

Deletes a quote adjustment and recalculates totals.

**Tags:** Sales

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Quote adjustment deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/sales/quote-adjustments" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"quoteId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/sales/quote-adjustments`

List quote adjustments

Returns a paginated collection of quote adjustments that belong to the current organization.

**Tags:** Sales

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| quoteId | 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 quote adjustments

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "quote_id": "00000000-0000-4000-8000-000000000000",
      "quote_line_id": null,
      "scope": "string",
      "kind": "string",
      "code": null,
      "label": null,
      "calculator_key": null,
      "promotion_id": null,
      "rate": 1,
      "amount_net": 1,
      "amount_gross": 1,
      "currency_code": null,
      "metadata": null,
      "position": 1,
      "created_at": "string",
      "updated_at": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sales/quote-adjustments?page=1&pageSize=50" \
  -H "Accept: application/json"
```

## POST `/sales/quote-adjustments`

Create quote adjustment

Creates a quote adjustment and recalculates totals.

**Tags:** Sales

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "quoteId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**201** – Quote adjustment created

Content-Type: `application/json`

```json
{
  "id": null,
  "quoteId": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/sales/quote-adjustments" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"quoteId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## PUT `/sales/quote-adjustments`

Update quote adjustment

Updates a quote adjustment and recalculates totals.

**Tags:** Sales

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "quoteId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Quote adjustment updated

Content-Type: `application/json`

```json
{
  "id": null,
  "quoteId": null
}
```

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/sales/quote-adjustments" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"quoteId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## DELETE `/sales/quote-lines`

Delete quote line

Deletes a quote line and recalculates totals.

**Tags:** Sales

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Quote line deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/sales/quote-lines" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"quoteId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/sales/quote-lines`

List quote lines

Returns a paginated collection of quote lines that belong to the current organization.

**Tags:** Sales

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| id | query | any | Optional |
| quoteId | 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 quote lines

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "quote_id": "00000000-0000-4000-8000-000000000000",
      "line_number": 1,
      "kind": "string",
      "status_entry_id": null,
      "status": null,
      "product_id": null,
      "product_variant_id": null,
      "catalog_snapshot": null,
      "name": null,
      "description": null,
      "comment": null,
      "quantity": 1,
      "quantity_unit": null,
      "normalized_quantity": 1,
      "normalized_unit": null,
      "uom_snapshot": null,
      "currency_code": "string",
      "unit_price_net": 1,
      "unit_price_gross": 1,
      "discount_amount": 1,
      "discount_percent": 1,
      "tax_rate": 1,
      "tax_amount": 1,
      "total_net_amount": 1,
      "total_gross_amount": 1,
      "configuration": null,
      "promotion_code": null,
      "promotion_snapshot": null,
      "metadata": null,
      "custom_field_set_id": null,
      "created_at": "string",
      "updated_at": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sales/quote-lines?page=1&pageSize=50" \
  -H "Accept: application/json"
```

## POST `/sales/quote-lines`

Create quote line

Creates a quote line and recalculates totals.

**Tags:** Sales

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "quoteId": "00000000-0000-4000-8000-000000000000",
  "currencyCode": "string",
  "uomSnapshot": null,
  "quantity": 1,
  "normalizedUnit": null
}
```

### Responses

**201** – Quote line created

Content-Type: `application/json`

```json
{
  "id": null,
  "quoteId": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/sales/quote-lines" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"quoteId\": \"00000000-0000-4000-8000-000000000000\",
  \"currencyCode\": \"string\",
  \"uomSnapshot\": null,
  \"quantity\": 1,
  \"normalizedUnit\": null
}"
```

## PUT `/sales/quote-lines`

Update quote line

Updates a quote line and recalculates totals.

**Tags:** Sales

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "quoteId": "00000000-0000-4000-8000-000000000000",
  "currencyCode": "string",
  "uomSnapshot": null,
  "quantity": 1,
  "normalizedUnit": null
}
```

### Responses

**200** – Quote line updated

Content-Type: `application/json`

```json
{
  "id": null,
  "quoteId": null
}
```

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/sales/quote-lines" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"quoteId\": \"00000000-0000-4000-8000-000000000000\",
  \"currencyCode\": \"string\",
  \"uomSnapshot\": null,
  \"quantity\": 1,
  \"normalizedUnit\": null
}"
```

## DELETE `/sales/quotes`

Delete quote

Deletes a sales quote.

Requires features: sales.quotes.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.quotes.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Quote deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/sales/quotes" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/sales/quotes`

List quotes

Returns a paginated collection of quotes that belong to the current organization.

Requires features: sales.quotes.view

**Tags:** Sales

**Requires authentication.**

**Features:** sales.quotes.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| id | query | any | Optional |
| customerId | query | any | Optional |
| channelId | query | any | Optional |
| lineItemCountMin | query | any | Optional |
| lineItemCountMax | query | any | Optional |
| totalNetMin | query | any | Optional |
| totalNetMax | query | any | Optional |
| totalGrossMin | query | any | Optional |
| totalGrossMax | query | any | Optional |
| dateFrom | query | any | Optional |
| dateTo | query | any | Optional |
| tagIds | query | any | Optional |
| tagIdsEmpty | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| withDeleted | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated quotes

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "quoteNumber": null,
      "status": null,
      "statusEntryId": null,
      "customerEntityId": null,
      "customerContactId": null,
      "billingAddressId": null,
      "shippingAddressId": null,
      "customerReference": null,
      "externalReference": null,
      "comment": null,
      "placedAt": null,
      "expectedDeliveryAt": null,
      "customerSnapshot": null,
      "billingAddressSnapshot": null,
      "shippingAddressSnapshot": null,
      "shippingMethodId": null,
      "shippingMethodCode": null,
      "shippingMethodSnapshot": null,
      "paymentMethodId": null,
      "paymentMethodCode": null,
      "paymentMethodSnapshot": null,
      "currencyCode": null,
      "channelId": null,
      "organizationId": null,
      "tenantId": null,
      "validFrom": null,
      "validUntil": null,
      "lineItemCount": null,
      "subtotalNetAmount": null,
      "subtotalGrossAmount": null,
      "discountTotalAmount": null,
      "taxTotalAmount": null,
      "shippingNetAmount": null,
      "shippingGrossAmount": null,
      "surchargeTotalAmount": null,
      "grandTotalNetAmount": null,
      "grandTotalGrossAmount": null,
      "paidTotalAmount": null,
      "refundedTotalAmount": null,
      "outstandingAmount": null,
      "createdAt": "string",
      "updatedAt": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sales/quotes?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/sales/quotes`

Create quote

Creates a new sales quote.

Requires features: sales.quotes.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.quotes.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "currencyCode": "string"
}
```

### Responses

**201** – Quote created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/sales/quotes" \
  -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\",
  \"currencyCode\": \"string\"
}"
```

## PUT `/sales/quotes`

Quote management

Requires features: sales.quotes.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.quotes.manage

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/sales/quotes" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/sales/quotes/accept`

Accept quote and convert to order

**Tags:** Sales

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Quote accepted and order created

Content-Type: `application/json`

```json
{
  "orderId": "00000000-0000-4000-8000-000000000000",
  "orderNumber": "string"
}
```

**400** – Invalid or expired quote

Content-Type: `application/json`

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

**404** – Quote not found

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/sales/quotes/accept" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"token\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## POST `/sales/quotes/convert`

Convert quote

Creates a sales order from a quote and removes the original quote record.

Requires features: sales.quotes.manage, sales.orders.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.quotes.manage, sales.orders.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Conversion succeeded

Content-Type: `application/json`

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

**400** – Invalid payload

Content-Type: `application/json`

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

**409** – Conflict detected

Content-Type: `application/json`

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

**423** – Record locked

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/sales/quotes/convert" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"quoteId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/sales/quotes/public/{token}`

Get quote details by acceptance token

**Tags:** Sales

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

### Responses

**200** – Quote details

Content-Type: `application/json`

```json
{
  "quote": {
    "quoteNumber": "string",
    "currencyCode": "string",
    "validFrom": null,
    "validUntil": null,
    "status": null,
    "subtotalNetAmount": "string",
    "subtotalGrossAmount": "string",
    "discountTotalAmount": "string",
    "taxTotalAmount": "string",
    "grandTotalNetAmount": "string",
    "grandTotalGrossAmount": "string"
  },
  "lines": [
    {
      "lineNumber": null,
      "kind": "string",
      "name": null,
      "description": null,
      "quantity": "string",
      "quantityUnit": null,
      "normalizedQuantity": "string",
      "normalizedUnit": null,
      "uomSnapshot": null,
      "currencyCode": "string",
      "unitPriceNet": "string",
      "unitPriceGross": "string",
      "discountAmount": "string",
      "discountPercent": "string",
      "taxRate": "string",
      "taxAmount": "string",
      "totalNetAmount": "string",
      "totalGrossAmount": "string",
      "unitPriceReference": null
    }
  ],
  "adjustments": [
    {
      "scope": null,
      "kind": null,
      "label": null,
      "rate": null,
      "amountNet": null,
      "amountGross": null,
      "currencyCode": null,
      "position": null,
      "quoteLineId": null
    }
  ],
  "isExpired": true
}
```

**404** – Quote not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sales/quotes/public/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json"
```

## POST `/sales/quotes/send`

Send quote

Requires features: sales.quotes.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.quotes.manage

### Request Body

Content-Type: `application/json`

```json
{
  "quoteId": "00000000-0000-4000-8000-000000000000",
  "validForDays": 14
}
```

### Responses

**200** – Email queued

Content-Type: `application/json`

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

**400** – Invalid payload

Content-Type: `application/json`

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

**404** – Not found

Content-Type: `application/json`

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

**409** – Conflict detected

Content-Type: `application/json`

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

**423** – Record locked

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/sales/quotes/send" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"quoteId\": \"00000000-0000-4000-8000-000000000000\",
  \"validForDays\": 14
}"
```

## GET `/sales/returns`

List returns

**Tags:** Sales

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

### Responses

**200** – Returns list

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "order_id": "00000000-0000-4000-8000-000000000000",
      "return_number": "string",
      "status_entry_id": null,
      "status": null,
      "reason": null,
      "notes": null,
      "returned_at": null,
      "created_at": "string",
      "updated_at": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sales/returns?page=1&pageSize=50" \
  -H "Accept: application/json"
```

## POST `/sales/returns`

Create return

**Tags:** Sales

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "orderId": "00000000-0000-4000-8000-000000000000",
  "lines": [
    {
      "orderLineId": "00000000-0000-4000-8000-000000000000",
      "quantity": 1
    }
  ]
}
```

### Responses

**201** – Return created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/sales/returns" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"orderId\": \"00000000-0000-4000-8000-000000000000\",
  \"lines\": [
    {
      \"orderLineId\": \"00000000-0000-4000-8000-000000000000\",
      \"quantity\": 1
    }
  ]
}"
```

## GET `/sales/returns/{id}`

Get return details

Requires features: sales.returns.view

**Tags:** Sales

**Requires authentication.**

**Features:** sales.returns.view

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

### Responses

**200** – Return details

Content-Type: `application/json`

```json
{
  "return": {
    "id": "00000000-0000-4000-8000-000000000000",
    "orderId": "00000000-0000-4000-8000-000000000000",
    "returnNumber": "string",
    "statusEntryId": null,
    "status": null,
    "reason": null,
    "notes": null,
    "returnedAt": null,
    "createdAt": null,
    "updatedAt": null,
    "totalNetAmount": 1,
    "totalGrossAmount": 1
  },
  "lines": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "orderLineId": null,
      "quantityReturned": "string",
      "unitPriceNet": "string",
      "unitPriceGross": "string",
      "totalNetAmount": "string",
      "totalGrossAmount": "string"
    }
  ]
}
```

**404** – Not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sales/returns/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/sales/settings/document-numbers`

Get document numbering settings

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Responses

**200** – Current numbering formats and counters

Content-Type: `application/json`

```json
{
  "orderNumberFormat": "string",
  "quoteNumberFormat": "string",
  "nextOrderNumber": 1,
  "nextQuoteNumber": 1
}
```

**400** – Missing scope

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sales/settings/document-numbers" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/sales/settings/document-numbers`

Update document numbering settings

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "orderNumberFormat": "string",
  "quoteNumberFormat": "string",
  "orderCustomerEditableStatuses": null,
  "orderAddressEditableStatuses": null
}
```

### Responses

**200** – Updated numbering formats and counters

Content-Type: `application/json`

```json
{
  "orderNumberFormat": "string",
  "quoteNumberFormat": "string",
  "nextOrderNumber": 1,
  "nextQuoteNumber": 1
}
```

**400** – Invalid payload

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/sales/settings/document-numbers" \
  -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\",
  \"orderNumberFormat\": \"string\",
  \"quoteNumberFormat\": \"string\",
  \"orderCustomerEditableStatuses\": null,
  \"orderAddressEditableStatuses\": null
}"
```

## GET `/sales/settings/order-editing`

Get order editing guards

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Responses

**200** – Current order editing guards

Content-Type: `application/json`

```json
{
  "orderCustomerEditableStatuses": null,
  "orderAddressEditableStatuses": null,
  "orderStatuses": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "value": "string",
      "label": "string"
    }
  ]
}
```

**400** – Missing scope

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sales/settings/order-editing" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/sales/settings/order-editing`

Update order editing guards

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "orderCustomerEditableStatuses": null,
  "orderAddressEditableStatuses": null
}
```

### Responses

**200** – Updated order editing guards

Content-Type: `application/json`

```json
{
  "orderCustomerEditableStatuses": null,
  "orderAddressEditableStatuses": null,
  "orderStatuses": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "value": "string",
      "label": "string"
    }
  ]
}
```

**400** – Invalid payload

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/sales/settings/order-editing" \
  -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\",
  \"orderCustomerEditableStatuses\": null,
  \"orderAddressEditableStatuses\": null
}"
```

## DELETE `/sales/shipment-statuses`

Delete shipment status

Deletes a shipment status identified by id.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Shipment status deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/sales/shipment-statuses" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/sales/shipment-statuses`

List shipment statuses

Manage the lifecycle states available for shipments.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### 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 shipment statuses

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "value": "string",
      "label": null,
      "color": null,
      "icon": null,
      "organizationId": null,
      "tenantId": null,
      "createdAt": "string",
      "updatedAt": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sales/shipment-statuses?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/sales/shipment-statuses`

Create shipment status

Creates a new shipment status.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "value": "string",
  "color": null,
  "icon": null
}
```

### Responses

**201** – Shipment status created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/sales/shipment-statuses" \
  -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\",
  \"value\": \"string\",
  \"color\": null,
  \"icon\": null
}"
```

## PUT `/sales/shipment-statuses`

Update shipment status

Updates an existing shipment status by id.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "color": null,
  "icon": null,
  "id": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**200** – Shipment status updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/sales/shipment-statuses" \
  -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\",
  \"color\": null,
  \"icon\": null,
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## DELETE `/sales/shipments`

Delete shipment

Deletes a shipment.

**Tags:** Sales

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Shipment deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/sales/shipments" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/sales/shipments`

List shipments

Returns a paginated collection of shipments that belong to the current organization.

**Tags:** Sales

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| orderId | 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 shipments

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "order_id": "00000000-0000-4000-8000-000000000000",
      "shipment_number": null,
      "shipping_method_id": null,
      "shipping_method_code": null,
      "shipping_method_name": null,
      "status_entry_id": null,
      "status": null,
      "status_label": null,
      "carrier_name": null,
      "tracking_numbers": null,
      "shipped_at": null,
      "delivered_at": null,
      "weight_value": null,
      "weight_unit": null,
      "declared_value_net": null,
      "declared_value_gross": null,
      "currency_code": null,
      "notes": null,
      "metadata": null,
      "custom_values": null,
      "customValues": null,
      "custom_fields": null,
      "customFields": null,
      "items_snapshot": null,
      "itemsSnapshot": null,
      "created_at": "string",
      "updated_at": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sales/shipments?page=1&pageSize=50" \
  -H "Accept: application/json"
```

## POST `/sales/shipments`

Create shipment

Creates a shipment for an order.

**Tags:** Sales

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "orderId": "00000000-0000-4000-8000-000000000000"
}
```

### Responses

**201** – Shipment created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/sales/shipments" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"orderId\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## PUT `/sales/shipments`

Update shipment

Updates a shipment.

**Tags:** Sales

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Shipment updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/sales/shipments" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## DELETE `/sales/shipping-methods`

Delete shipping method

Deletes a shipping method identified by id.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Shipping method deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/sales/shipping-methods" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/sales/shipping-methods`

List shipping methods

Maintain shipping services, carrier mappings, and pricing defaults for order fulfillment.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| currency | query | any | Optional |
| isActive | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| withDeleted | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |

### Responses

**200** – Paginated shipping methods

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "code": "string",
      "description": null,
      "carrierCode": null,
      "providerKey": null,
      "serviceLevel": null,
      "estimatedTransitDays": null,
      "baseRateNet": "string",
      "baseRateGross": "string",
      "currencyCode": null,
      "isActive": true,
      "metadata": null,
      "providerSettings": null,
      "organizationId": null,
      "tenantId": null,
      "createdAt": "string",
      "updatedAt": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sales/shipping-methods?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/sales/shipping-methods`

Create shipping method

Creates a new shipping method.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "name": "string",
  "code": "string"
}
```

### Responses

**201** – Shipping method created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/sales/shipping-methods" \
  -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\",
  \"code\": \"string\"
}"
```

## PUT `/sales/shipping-methods`

Update shipping method

Updates an existing shipping method by id.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Shipping method updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/sales/shipping-methods" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## DELETE `/sales/tags`

Delete sales tag

Deletes a sales tag.

Requires features: sales.orders.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.orders.manage

### Responses

**200** – Sales tag deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/sales/tags" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/sales/tags`

List sales tags

Manage reusable tags to categorize sales orders and quotes.

Requires features: sales.orders.view

**Tags:** Sales

**Requires authentication.**

**Features:** sales.orders.view

### 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 sales tags

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "slug": "string",
      "label": null,
      "color": null,
      "description": null,
      "organization_id": null,
      "tenant_id": null
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sales/tags?page=1&pageSize=100" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/sales/tags`

Create sales tag

Creates a sales document tag.

Requires features: sales.orders.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.orders.manage

### 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** – Sales tag created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/sales/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 `/sales/tags`

Update sales tag

Updates an existing sales tag.

Requires features: sales.orders.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.orders.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Sales tag updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/sales/tags" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## DELETE `/sales/tax-rates`

Delete tax rate

Deletes a tax rate identified by `id`.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Deletion acknowledgement

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/sales/tax-rates" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/sales/tax-rates`

List tax rates

Returns a paginated list of sales tax rates for the current organization.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| country | query | any | Optional |
| region | query | any | Optional |
| channelId | query | any | Optional |
| isCompound | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |
| withDeleted | query | any | Optional |

### Responses

**200** – Paginated list of tax rates

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "name": "string",
      "code": null,
      "rate": 1,
      "countryCode": null,
      "regionCode": null,
      "postalCode": null,
      "city": null,
      "customerGroupId": null,
      "productCategoryId": null,
      "channelId": null,
      "priority": null,
      "isCompound": true,
      "isDefault": true,
      "metadata": null,
      "startsAt": null,
      "endsAt": null,
      "organizationId": null,
      "tenantId": null,
      "createdAt": "string",
      "updatedAt": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sales/tax-rates?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/sales/tax-rates`

Create tax rate

Creates a new tax rate record.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Request Body

Content-Type: `application/json`

```json
{
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "name": "string",
  "code": "string",
  "rate": 1
}
```

### Responses

**201** – Identifier of the created tax rate

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/sales/tax-rates" \
  -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\",
  \"code\": \"string\",
  \"rate\": 1
}"
```

## PUT `/sales/tax-rates`

Update tax rate

Updates an existing tax rate by identifier.

Requires features: sales.settings.manage

**Tags:** Sales

**Requires authentication.**

**Features:** sales.settings.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Update acknowledgement

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/sales/tax-rates" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## DELETE `/scheduler/jobs`

Delete scheduledjob

Deletes a scheduled job by ID.

Requires features: scheduler.jobs.manage

**Tags:** Scheduler

**Requires authentication.**

**Features:** scheduler.jobs.manage

### 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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: scheduler.jobs.view

**Tags:** Scheduler

**Requires authentication.**

**Features:** scheduler.jobs.view

### 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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: scheduler.jobs.manage

**Tags:** Scheduler

**Requires authentication.**

**Features:** scheduler.jobs.manage

### 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://crmprod.erp.sobota.myopenmercato.com/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.

Requires features: scheduler.jobs.manage

**Tags:** Scheduler

**Requires authentication.**

**Features:** scheduler.jobs.manage

### 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://crmprod.erp.sobota.myopenmercato.com/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://crmprod.erp.sobota.myopenmercato.com/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://crmprod.erp.sobota.myopenmercato.com/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 command IDs (from the command registry) 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://crmprod.erp.sobota.myopenmercato.com/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://crmprod.erp.sobota.myopenmercato.com/scheduler/trigger" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"string\"
}"
```

## GET `/search/embeddings`

Get embeddings configuration

Returns current embedding provider and model configuration.

Requires features: search.embeddings.view

**Tags:** Search

**Requires authentication.**

**Features:** search.embeddings.view

### Responses

**200** – Embeddings settings

Content-Type: `application/json`

```json
{
  "settings": {
    "openaiConfigured": true,
    "autoIndexingEnabled": true,
    "autoIndexingLocked": true,
    "lockReason": null,
    "embeddingConfig": null,
    "configuredProviders": [
      "openai"
    ],
    "indexedDimension": null,
    "reindexRequired": true,
    "documentCount": null
  }
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/search/embeddings" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/search/embeddings`

Update embeddings configuration

Updates the embedding provider and model settings.

Requires features: search.embeddings.manage

**Tags:** Search

**Requires authentication.**

**Features:** search.embeddings.manage

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Updated settings

Content-Type: `application/json`

```json
{
  "settings": {
    "openaiConfigured": true,
    "autoIndexingEnabled": true,
    "autoIndexingLocked": true,
    "lockReason": null,
    "embeddingConfig": null,
    "configuredProviders": [
      "openai"
    ],
    "indexedDimension": null,
    "reindexRequired": true,
    "documentCount": null
  }
}
```

**400** – Invalid request

Content-Type: `application/json`

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

**409** – Auto-indexing disabled via environment

Content-Type: `application/json`

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

**500** – Update failed

Content-Type: `application/json`

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

**503** – Configuration service unavailable

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/search/embeddings" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## POST `/search/embeddings/reindex`

Trigger vector reindex

Starts a vector embedding reindex operation.

Requires features: search.embeddings.manage

**Tags:** Search

**Requires authentication.**

**Features:** search.embeddings.manage

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Reindex result

Content-Type: `application/json`

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

**409** – Reindex already in progress

Content-Type: `application/json`

```json
{
  "error": "string",
  "lock": {
    "type": "fulltext",
    "action": "string",
    "startedAt": "string",
    "elapsedMinutes": 1,
    "processedCount": null,
    "totalCount": null
  }
}
```

**500** – Reindex failed

Content-Type: `application/json`

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

**503** – Search indexer unavailable

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/search/embeddings/reindex" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## POST `/search/embeddings/reindex/cancel`

Cancel vector reindex

Cancels an in-progress vector reindex operation.

Requires features: search.embeddings.manage

**Tags:** Search

**Requires authentication.**

**Features:** search.embeddings.manage

### Responses

**200** – Cancel result

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/search/embeddings/reindex/cancel" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/search/index`

Purge vector index

Purges entries from the vector search index. Requires confirmAll=true when purging all entities.

Requires features: search.embeddings.manage

**Tags:** Search

**Requires authentication.**

**Features:** search.embeddings.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| entityId | query | any | Optional. Specific entity ID to purge (e.g., "customers:customer_person_profile", "catalog:catalog_product") |
| confirmAll | query | any | Optional. Required when purging all entities |

### Responses

**200** – Purge result

Content-Type: `application/json`

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

**400** – Missing confirmAll parameter

Content-Type: `application/json`

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

**500** – Purge failed

Content-Type: `application/json`

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

**503** – Search indexer unavailable

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/search/index" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/search/index`

List vector index entries

Returns paginated list of entries in the vector search index.

Requires features: search.view

**Tags:** Search

**Requires authentication.**

**Features:** search.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| entityId | query | any | Optional. Filter by entity ID (e.g., "customers:customer_person_profile", "catalog:catalog_product") |
| limit | query | any | Optional. Maximum entries to return (default: 50, max: 200) |
| offset | query | any | Optional. Offset for pagination (default: 0) |

### Responses

**200** – Index entries

Content-Type: `application/json`

```json
{
  "entries": [
    {
      "id": "string",
      "entityId": "string",
      "recordId": "string",
      "tenantId": "string",
      "organizationId": null
    }
  ],
  "limit": 1,
  "offset": 1
}
```

**500** – Failed to fetch index

Content-Type: `application/json`

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

**503** – Vector strategy unavailable

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/search/index" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/search/reindex`

Trigger fulltext reindex

Starts a fulltext (Meilisearch) reindex operation. Can clear, recreate, or fully reindex.

Requires features: search.reindex

**Tags:** Search

**Requires authentication.**

**Features:** search.reindex

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Reindex result

Content-Type: `application/json`

```json
{
  "ok": true,
  "action": "clear",
  "entityId": null
}
```

**409** – Reindex already in progress

Content-Type: `application/json`

```json
{
  "error": "string",
  "lock": {
    "type": "fulltext",
    "action": "string",
    "startedAt": "string",
    "elapsedMinutes": 1,
    "processedCount": null,
    "totalCount": null
  }
}
```

**500** – Reindex failed

Content-Type: `application/json`

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

**503** – Search service unavailable

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/search/reindex" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## POST `/search/reindex/cancel`

Cancel fulltext reindex

Cancels an in-progress fulltext reindex operation.

Requires features: search.reindex

**Tags:** Search

**Requires authentication.**

**Features:** search.reindex

### Responses

**200** – Cancel result

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/search/reindex/cancel" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/search/search`

Search across all indexed entities

Performs a search using configured strategies (fulltext, vector, tokens). Use for search playground.

Requires features: search.view

**Tags:** Search

**Requires authentication.**

**Features:** search.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| q | query | any | Required. Search query (required) |
| limit | query | any | Optional. Maximum results to return (default: 50, max: 100) |
| strategies | query | any | Optional. Comma-separated strategies to use: fulltext, vector, tokens (e.g., "fulltext,vector") |
| entityTypes | query | any | Optional. Comma-separated entity types to filter results (e.g., "customers:customer_person_profile,catalog:catalog_product,sales:sales_order") |

### Responses

**200** – Search results

Content-Type: `application/json`

```json
{
  "results": [
    {
      "entityId": "string",
      "recordId": "string",
      "score": 1,
      "source": "fulltext"
    }
  ],
  "strategiesUsed": [
    "fulltext"
  ],
  "timing": 1,
  "query": "string",
  "limit": 1
}
```

**400** – Missing query parameter

Content-Type: `application/json`

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

**500** – Search failed

Content-Type: `application/json`

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

**503** – Search service unavailable

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/search/search?q=string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/search/search/global`

Global search (Cmd+K)

Performs a global search using saved tenant strategies. Does NOT accept strategies from URL.

Requires features: search.view

**Tags:** Search

**Requires authentication.**

**Features:** search.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| q | query | any | Required. Search query (required) |
| limit | query | any | Optional. Maximum results to return (default: 50, max: 100) |
| entityTypes | query | any | Optional. Comma-separated entity types to filter results (e.g., "customers:customer_person_profile,catalog:catalog_product,sales:sales_order") |

### Responses

**200** – Search results

Content-Type: `application/json`

```json
{
  "results": [
    {
      "entityId": "string",
      "recordId": "string",
      "score": 1,
      "source": "fulltext"
    }
  ],
  "strategiesUsed": [
    "fulltext"
  ],
  "strategiesEnabled": [
    "fulltext"
  ],
  "timing": 1,
  "query": "string",
  "limit": 1
}
```

**400** – Missing query parameter

Content-Type: `application/json`

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

**500** – Search failed

Content-Type: `application/json`

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

**503** – Search service unavailable

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/search/search/global?q=string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/search/settings`

Get search settings and status

Returns search module configuration, available strategies, and reindex lock status.

Requires features: search.view

**Tags:** Search

**Requires authentication.**

**Features:** search.view

### Responses

**200** – Search settings

Content-Type: `application/json`

```json
{
  "settings": {
    "strategies": [
      {
        "id": "string",
        "name": "string",
        "priority": 1,
        "available": true
      }
    ],
    "fulltextConfigured": true,
    "fulltextStats": null,
    "vectorConfigured": true,
    "tokensEnabled": true,
    "defaultStrategies": [
      "string"
    ],
    "reindexLock": null,
    "fulltextReindexLock": null,
    "vectorReindexLock": null
  }
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/search/settings" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/search/settings/fulltext`

Get fulltext search configuration

Returns Meilisearch configuration status and index statistics.

Requires features: search.view

**Tags:** Search

**Requires authentication.**

**Features:** search.view

### Responses

**200** – Fulltext settings

Content-Type: `application/json`

```json
{
  "driver": null,
  "configured": true,
  "envVars": {
    "MEILISEARCH_HOST": {
      "set": true,
      "hint": "string"
    },
    "MEILISEARCH_API_KEY": {
      "set": true,
      "hint": "string"
    }
  },
  "optionalEnvVars": {
    "MEILISEARCH_INDEX_PREFIX": {
      "set": true,
      "hint": "string"
    },
    "SEARCH_EXCLUDE_ENCRYPTED_FIELDS": {
      "set": true,
      "hint": "string"
    }
  }
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/search/settings/fulltext" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/search/settings/global-search`

Get global search strategies

Returns the enabled strategies for Cmd+K global search.

Requires features: search.view

**Tags:** Search

**Requires authentication.**

**Features:** search.view

### Responses

**200** – Global search settings

Content-Type: `application/json`

```json
{
  "enabledStrategies": [
    "fulltext"
  ]
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/search/settings/global-search" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/search/settings/global-search`

Update global search strategies

Sets which strategies are enabled for Cmd+K global search.

Requires features: search.manage

**Tags:** Search

**Requires authentication.**

**Features:** search.manage

### Request Body

Content-Type: `application/json`

```json
{
  "enabledStrategies": [
    "fulltext"
  ]
}
```

### Responses

**200** – Updated settings

Content-Type: `application/json`

```json
{
  "ok": true,
  "enabledStrategies": [
    "fulltext"
  ]
}
```

**400** – Invalid request

Content-Type: `application/json`

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

**500** – Internal error

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/search/settings/global-search" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"enabledStrategies\": [
    \"fulltext\"
  ]
}"
```

## GET `/search/settings/vector-store`

Get vector store configuration

Returns vector store configuration status.

Requires features: search.view

**Tags:** Search

**Requires authentication.**

**Features:** search.view

### Responses

**200** – Vector store settings

Content-Type: `application/json`

```json
{
  "currentDriver": "pgvector",
  "configured": true,
  "drivers": [
    {
      "id": "pgvector",
      "name": "string",
      "configured": true,
      "implemented": true,
      "envVars": [
        {
          "name": "string",
          "set": true,
          "hint": "string"
        }
      ]
    }
  ]
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/search/settings/vector-store" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/shipping-carriers/cancel`

Cancel shipment

Requires features: shipping_carriers.manage

**Tags:** ShippingCarriers

**Requires authentication.**

**Features:** shipping_carriers.manage

### Responses

**200** – Shipment cancelled

Content-Type: `application/json`

**422** – Validation failed or shipment cannot be cancelled in its current status

Content-Type: `application/json`

**502** – Provider upstream error

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/shipping-carriers/cancel" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/shipping-carriers/points`

Search carrier drop-off points (lockers, POP points)

Requires features: shipping_carriers.view

**Tags:** ShippingCarriers

**Requires authentication.**

**Features:** shipping_carriers.view

### Responses

**200** – Points returned

Content-Type: `application/json`

**422** – Validation failed

Content-Type: `application/json`

**502** – Provider upstream error or unsupported

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/shipping-carriers/points" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/shipping-carriers/providers`

List registered shipping providers

Requires features: shipping_carriers.manage

**Tags:** ShippingCarriers

**Requires authentication.**

**Features:** shipping_carriers.manage

### Responses

**200** – List of registered provider keys

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/shipping-carriers/providers" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/shipping-carriers/rates`

Calculate shipping rates

Requires features: shipping_carriers.manage

**Tags:** ShippingCarriers

**Requires authentication.**

**Features:** shipping_carriers.manage

### Responses

**200** – Rates calculated

Content-Type: `application/json`

**422** – Validation failed

Content-Type: `application/json`

**502** – Provider upstream error

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/shipping-carriers/rates" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/shipping-carriers/shipments`

Create shipment

Requires features: shipping_carriers.manage

**Tags:** ShippingCarriers

**Requires authentication.**

**Features:** shipping_carriers.manage

### Responses

**201** – Shipment created

Content-Type: `application/json`

**422** – Validation failed

Content-Type: `application/json`

**502** – Provider upstream error

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/shipping-carriers/shipments" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/shipping-carriers/tracking`

Get tracking

Requires features: shipping_carriers.view

**Tags:** ShippingCarriers

**Requires authentication.**

**Features:** shipping_carriers.view

### Responses

**200** – Tracking returned

Content-Type: `application/json`

**422** – Validation failed

Content-Type: `application/json`

**502** – Provider upstream error

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/shipping-carriers/tracking" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/shipping-carriers/webhook/{provider}`

Process inbound carrier webhook

**Tags:** ShippingCarriers

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

### Responses

**202** – Webhook accepted for async processing

Content-Type: `application/json`

**401** – Signature verification failed

Content-Type: `application/json`

**404** – Unknown provider

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/shipping-carriers/webhook/:provider" \
  -H "Accept: application/json"
```

## DELETE `/staff/activities`

Delete teammemberactivity

Deletes a team member activity.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – TeamMemberActivity deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/staff/activities" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/staff/activities`

List teammemberactivitys

Returns a paginated collection of teammemberactivitys scoped to the authenticated organization.

Requires features: staff.view

**Tags:** Staff

**Requires authentication.**

**Features:** staff.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| entityId | 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 teammemberactivitys

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "member_id": null,
      "activity_type": null,
      "subject": null,
      "body": null,
      "occurred_at": 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://crmprod.erp.sobota.myopenmercato.com/staff/activities?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/staff/activities`

Create teammemberactivity

Adds an activity to a team member timeline.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "entityId": "00000000-0000-4000-8000-000000000000",
  "activityType": "string",
  "appearanceIcon": null,
  "appearanceColor": null
}
```

### Responses

**201** – TeamMemberActivity created

Content-Type: `application/json`

```json
{
  "id": null,
  "authorUserId": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/staff/activities" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"entityId\": \"00000000-0000-4000-8000-000000000000\",
  \"activityType\": \"string\",
  \"appearanceIcon\": null,
  \"appearanceColor\": null
}"
```

## PUT `/staff/activities`

Update teammemberactivity

Updates a team member activity.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – TeamMemberActivity updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/staff/activities" \
  -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 `/staff/addresses`

Delete teammemberaddress

Deletes a team member address.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – TeamMemberAddress deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/staff/addresses" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/staff/addresses`

List teammemberaddresss

Returns a paginated collection of teammemberaddresss scoped to the authenticated organization.

Requires features: staff.view

**Tags:** Staff

**Requires authentication.**

**Features:** staff.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| entityId | 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 teammemberaddresss

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "member_id": null,
      "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,
      "created_at": null,
      "updated_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/staff/addresses?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/staff/addresses`

Create teammemberaddress

Adds a team member address.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "entityId": "00000000-0000-4000-8000-000000000000",
  "addressLine1": "string"
}
```

### Responses

**201** – TeamMemberAddress created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/staff/addresses" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"entityId\": \"00000000-0000-4000-8000-000000000000\",
  \"addressLine1\": \"string\"
}"
```

## PUT `/staff/addresses`

Update teammemberaddress

Updates a team member address.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – TeamMemberAddress updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/staff/addresses" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## DELETE `/staff/comments`

Delete teammembercomment

Deletes a team member note.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – TeamMemberComment deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/staff/comments" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/staff/comments`

List teammembercomments

Returns a paginated collection of teammembercomments scoped to the authenticated organization.

Requires features: staff.view

**Tags:** Staff

**Requires authentication.**

**Features:** staff.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| entityId | 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 teammembercomments

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "member_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://crmprod.erp.sobota.myopenmercato.com/staff/comments?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/staff/comments`

Create teammembercomment

Adds a note to a team member timeline.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "entityId": "00000000-0000-4000-8000-000000000000",
  "body": "string",
  "appearanceIcon": null,
  "appearanceColor": null
}
```

### Responses

**201** – TeamMemberComment created

Content-Type: `application/json`

```json
{
  "id": null,
  "authorUserId": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/staff/comments" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"entityId\": \"00000000-0000-4000-8000-000000000000\",
  \"body\": \"string\",
  \"appearanceIcon\": null,
  \"appearanceColor\": null
}"
```

## PUT `/staff/comments`

Update teammembercomment

Updates a team member note.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – TeamMemberComment updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/staff/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 `/staff/job-histories`

Delete teammemberjobhistory

Deletes a team member job history entry.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – TeamMemberJobHistory deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/staff/job-histories" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/staff/job-histories`

List teammemberjobhistorys

Returns a paginated collection of teammemberjobhistorys scoped to the authenticated organization.

Requires features: staff.view

**Tags:** Staff

**Requires authentication.**

**Features:** staff.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| entityId | 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 teammemberjobhistorys

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "member_id": null,
      "name": null,
      "company_name": null,
      "description": null,
      "start_date": null,
      "end_date": null,
      "organization_id": null,
      "tenant_id": null,
      "created_at": null,
      "updated_at": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/staff/job-histories?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/staff/job-histories`

Create teammemberjobhistory

Adds a team member job history entry.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "entityId": "00000000-0000-4000-8000-000000000000",
  "name": "string",
  "companyName": null,
  "description": null,
  "startDate": "2025-01-01T00:00:00.000Z",
  "endDate": null
}
```

### Responses

**201** – TeamMemberJobHistory created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/staff/job-histories" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"entityId\": \"00000000-0000-4000-8000-000000000000\",
  \"name\": \"string\",
  \"companyName\": null,
  \"description\": null,
  \"startDate\": \"2025-01-01T00:00:00.000Z\",
  \"endDate\": null
}"
```

## PUT `/staff/job-histories`

Update teammemberjobhistory

Updates a team member job history entry.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "companyName": null,
  "description": null,
  "endDate": null
}
```

### Responses

**200** – TeamMemberJobHistory updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/staff/job-histories" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"companyName\": null,
  \"description\": null,
  \"endDate\": null
}"
```

## DELETE `/staff/leave-requests`

Delete leave request

Deletes a leave request by id.

**Tags:** Staff

**Requires authentication.**

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Leave request deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/staff/leave-requests" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/staff/leave-requests`

List leave requests

Returns a paginated collection of leave requests scoped to the authenticated organization.

**Tags:** Staff

**Requires authentication.**

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| status | query | any | Optional |
| memberId | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |

### Responses

**200** – Paginated leave requests

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": null,
      "organization_id": null,
      "tenant_id": null,
      "member_id": null,
      "start_date": null,
      "end_date": null,
      "timezone": null,
      "status": null,
      "unavailability_reason_entry_id": null,
      "unavailability_reason_value": null,
      "note": null,
      "decision_comment": null,
      "submitted_by_user_id": null,
      "decided_by_user_id": null,
      "decided_at": null,
      "created_at": null,
      "updated_at": null,
      "member": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/staff/leave-requests?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/staff/leave-requests`

Create leave request

Creates a leave request for a staff member.

**Tags:** Staff

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "memberId": "00000000-0000-4000-8000-000000000000",
  "timezone": "string",
  "startDate": "2025-01-01T00:00:00.000Z",
  "endDate": "2025-01-01T00:00:00.000Z",
  "unavailabilityReasonEntryId": null,
  "unavailabilityReasonValue": null,
  "note": null,
  "submittedByUserId": null
}
```

### Responses

**201** – Leave request created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/staff/leave-requests" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"memberId\": \"00000000-0000-4000-8000-000000000000\",
  \"timezone\": \"string\",
  \"startDate\": \"2025-01-01T00:00:00.000Z\",
  \"endDate\": \"2025-01-01T00:00:00.000Z\",
  \"unavailabilityReasonEntryId\": null,
  \"unavailabilityReasonValue\": null,
  \"note\": null,
  \"submittedByUserId\": null
}"
```

## PUT `/staff/leave-requests`

Update leave request

Updates a leave request by id.

**Tags:** Staff

**Requires authentication.**

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "unavailabilityReasonEntryId": null,
  "unavailabilityReasonValue": null,
  "note": null
}
```

### Responses

**200** – Leave request updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/staff/leave-requests" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"unavailabilityReasonEntryId\": null,
  \"unavailabilityReasonValue\": null,
  \"note\": null
}"
```

## POST `/staff/leave-requests/accept`

Approve leave request

Approves a leave request and adds unavailability rules for the staff member.

Requires features: staff.leave_requests.manage

**Tags:** Staff

**Requires authentication.**

**Features:** staff.leave_requests.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Leave request approved

Content-Type: `application/json`

```json
{
  "ok": true,
  "id": null
}
```

**400** – Invalid payload

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/staff/leave-requests/accept" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"decisionComment\": null,
  \"decidedByUserId\": null
}"
```

## POST `/staff/leave-requests/reject`

Reject leave request

Rejects a leave request with an optional comment.

Requires features: staff.leave_requests.manage

**Tags:** Staff

**Requires authentication.**

**Features:** staff.leave_requests.manage

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Leave request rejected

Content-Type: `application/json`

```json
{
  "ok": true,
  "id": null
}
```

**400** – Invalid payload

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/staff/leave-requests/reject" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"decisionComment\": null,
  \"decidedByUserId\": null
}"
```

## DELETE `/staff/team-members`

Delete team member

Deletes a team member by id.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Team member deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/staff/team-members" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/staff/team-members`

List team members

Returns a paginated collection of team members scoped to the authenticated organization.

Requires features: staff.view

**Tags:** Staff

**Requires authentication.**

**Features:** staff.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| isActive | query | any | Optional |
| teamId | query | any | Optional |
| roleId | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |

### Responses

**200** – Paginated team members

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": null,
      "organization_id": null,
      "tenant_id": null,
      "team_id": null,
      "display_name": null,
      "description": null,
      "user_id": null,
      "availability_rule_set_id": null,
      "is_active": null,
      "created_at": null,
      "updated_at": null,
      "user": null,
      "team": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/staff/team-members?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/staff/team-members`

Create team member

Creates a team member for staff assignments.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "teamId": null,
  "displayName": "string",
  "description": null,
  "userId": null,
  "roleIds": [],
  "tags": [],
  "availabilityRuleSetId": null
}
```

### Responses

**201** – Team member created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/staff/team-members" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"teamId\": null,
  \"displayName\": \"string\",
  \"description\": null,
  \"userId\": null,
  \"roleIds\": [],
  \"tags\": [],
  \"availabilityRuleSetId\": null
}"
```

## PUT `/staff/team-members`

Update team member

Updates a team member by id.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "teamId": null,
  "description": null,
  "userId": null,
  "availabilityRuleSetId": null
}
```

### Responses

**200** – Team member updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/staff/team-members" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"teamId\": null,
  \"description\": null,
  \"userId\": null,
  \"availabilityRuleSetId\": null
}"
```

## GET `/staff/team-members/self`

Get current user team member profile

Returns the staff team member linked to the current user, if any.

Requires features: staff.leave_requests.send

**Tags:** Staff

**Requires authentication.**

**Features:** staff.leave_requests.send

### Responses

**200** – Team member profile

Content-Type: `application/json`

```json
{
  "member": null
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/staff/team-members/self" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/staff/team-members/self`

Create current user team member profile

Creates a team member profile for the signed-in user.

Requires features: staff.leave_requests.send

**Tags:** Staff

**Requires authentication.**

**Features:** staff.leave_requests.send

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "displayName": "string",
  "description": null
}
```

### Responses

**201** – Team member created

Content-Type: `application/json`

```json
{
  "id": null
}
```

**400** – Invalid payload

Content-Type: `application/json`

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

**409** – Already exists

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/staff/team-members/self" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"displayName\": \"string\",
  \"description\": null
}"
```

## POST `/staff/team-members/tags/assign`

Assign team member tag

Assigns a tag to a staff team member.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "memberId": "00000000-0000-4000-8000-000000000000",
  "tag": "string"
}
```

### Responses

**201** – Tag assignment created

Content-Type: `application/json`

```json
{
  "id": null
}
```

**400** – Invalid payload

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/staff/team-members/tags/assign" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"memberId\": \"00000000-0000-4000-8000-000000000000\",
  \"tag\": \"string\"
}"
```

## POST `/staff/team-members/tags/unassign`

Unassign team member tag

Removes a tag from a staff team member.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "memberId": "00000000-0000-4000-8000-000000000000",
  "tag": "string"
}
```

### Responses

**200** – Tag assignment removed

Content-Type: `application/json`

```json
{
  "id": null
}
```

**400** – Invalid payload

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/staff/team-members/tags/unassign" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"memberId\": \"00000000-0000-4000-8000-000000000000\",
  \"tag\": \"string\"
}"
```

## DELETE `/staff/team-roles`

Delete team role

Deletes a team role by id.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Team role deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/staff/team-roles" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/staff/team-roles`

List team roles

Returns a paginated collection of team roles scoped to the authenticated organization.

Requires features: staff.view

**Tags:** Staff

**Requires authentication.**

**Features:** staff.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |
| teamId | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |

### Responses

**200** – Paginated team roles

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": null,
      "organization_id": null,
      "tenant_id": null,
      "team_id": null,
      "name": null,
      "description": null,
      "appearance_icon": null,
      "appearance_color": null,
      "created_at": null,
      "updated_at": null,
      "team": null,
      "memberCount": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/staff/team-roles?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/staff/team-roles`

Create team role

Creates a team role for staff team members.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "teamId": null,
  "name": "string",
  "description": null,
  "appearanceIcon": null,
  "appearanceColor": null
}
```

### Responses

**201** – Team role created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/staff/team-roles" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"teamId\": null,
  \"name\": \"string\",
  \"description\": null,
  \"appearanceIcon\": null,
  \"appearanceColor\": null
}"
```

## PUT `/staff/team-roles`

Update team role

Updates a team role by id.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "id": "00000000-0000-4000-8000-000000000000",
  "teamId": null,
  "description": null,
  "appearanceIcon": null,
  "appearanceColor": null
}
```

### Responses

**200** – Team role updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/staff/team-roles" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"teamId\": null,
  \"description\": null,
  \"appearanceIcon\": null,
  \"appearanceColor\": null
}"
```

## DELETE `/staff/teams`

Delete team

Deletes a staff team by id.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Team deleted

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/staff/teams" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\"
}"
```

## GET `/staff/teams`

List teams

Returns a paginated collection of teams scoped to the authenticated organization.

Requires features: staff.view

**Tags:** Staff

**Requires authentication.**

**Features:** staff.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| search | query | any | Optional |
| ids | query | any | Optional. Comma-separated list of record UUIDs to filter by (max 200). |
| isActive | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |

### Responses

**200** – Paginated teams

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": null,
      "organization_id": null,
      "tenant_id": null,
      "name": null,
      "description": null,
      "is_active": null,
      "created_at": null,
      "updated_at": null,
      "memberCount": null
    }
  ],
  "total": 1,
  "totalPages": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/staff/teams?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/staff/teams`

Create team

Creates a staff team.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

```json
{
  "tenantId": "00000000-0000-4000-8000-000000000000",
  "organizationId": "00000000-0000-4000-8000-000000000000",
  "name": "string",
  "description": null
}
```

### Responses

**201** – Team created

Content-Type: `application/json`

```json
{
  "id": null
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/staff/teams" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"tenantId\": \"00000000-0000-4000-8000-000000000000\",
  \"organizationId\": \"00000000-0000-4000-8000-000000000000\",
  \"name\": \"string\",
  \"description\": null
}"
```

## PUT `/staff/teams`

Update team

Updates a staff team by id.

Requires features: staff.manage_team

**Tags:** Staff

**Requires authentication.**

**Features:** staff.manage_team

### Request Body

Content-Type: `application/json`

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

### Responses

**200** – Team updated

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/staff/teams" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"id\": \"00000000-0000-4000-8000-000000000000\",
  \"description\": null
}"
```

## GET `/sync_akeneo/custom-fields`

Inspect and create Akeneo-backed custom fields

Requires features: data_sync.configure

**Tags:** Akeneo Product Sync

**Requires authentication.**

**Features:** data_sync.configure

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sync_akeneo/custom-fields" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/sync_akeneo/custom-fields`

Inspect and create Akeneo-backed custom fields

Requires features: data_sync.configure

**Tags:** Akeneo Product Sync

**Requires authentication.**

**Features:** data_sync.configure

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/sync_akeneo/custom-fields" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/sync_akeneo/delete-products`

Start deleting all Akeneo-imported products for the current organization

Requires features: data_sync.configure

**Tags:** Akeneo Product Sync

**Requires authentication.**

**Features:** data_sync.configure

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/sync_akeneo/delete-products" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/sync_akeneo/discovery`

Load Akeneo discovery metadata for field mapping

Requires features: data_sync.configure

**Tags:** Akeneo Product Sync

**Requires authentication.**

**Features:** data_sync.configure

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sync_akeneo/discovery" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/sync_akeneo/first-import`

GET /sync_akeneo/first-import

Requires features: data_sync.configure

**Tags:** Akeneo Product Sync

**Requires authentication.**

**Features:** data_sync.configure

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/sync_akeneo/first-import" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/sync_akeneo/first-import`

POST /sync_akeneo/first-import

Requires features: data_sync.run

**Tags:** Akeneo Product Sync

**Requires authentication.**

**Features:** data_sync.run

### Responses

**201** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/sync_akeneo/first-import" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/translations/{entityType}/{entityId}`

Delete entity translations

Removes all translations for an entity.

Requires features: translations.manage

**Tags:** Translations

**Requires authentication.**

**Features:** translations.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| entityType | path | any | Required |
| entityId | path | any | Required |

### Responses

**204** – Translations deleted.

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/translations/string/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/translations/{entityType}/{entityId}`

Get entity translations

Returns the full translation record for a single entity.

Requires features: translations.view

**Tags:** Translations

**Requires authentication.**

**Features:** translations.view

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| entityType | path | any | Required |
| entityId | path | any | Required |

### Responses

**200** – Translation record found.

Content-Type: `application/json`

**404** – No translations found for this entity

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/translations/string/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/translations/{entityType}/{entityId}`

Create or update entity translations

Full replacement of translations JSONB for an entity.

Requires features: translations.manage

**Tags:** Translations

**Requires authentication.**

**Features:** translations.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| entityType | path | any | Required |
| entityId | path | any | Required |

### Responses

**200** – Translations saved.

Content-Type: `application/json`

**400** – Validation failed

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/translations/string/string" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/translations/locales`

GET /translations/locales

**Tags:** Entity Translations

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/translations/locales" \
  -H "Accept: application/json"
```

## PUT `/translations/locales`

PUT /translations/locales

**Tags:** Entity Translations

### Responses

**200** – Success response

Content-Type: `application/json`

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/translations/locales" \
  -H "Accept: application/json"
```

## GET `/webhooks`

List webhooks

Returns paginated webhooks for the current tenant and organization.

Requires features: webhooks.view

**Tags:** Webhooks

**Requires authentication.**

**Features:** webhooks.view

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

### Responses

**200** – Webhook collection

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "name": "string",
      "description": null,
      "url": "string",
      "subscribedEvents": [
        "string"
      ],
      "httpMethod": "string",
      "isActive": true,
      "deliveryStrategy": "string",
      "maxRetries": 1,
      "consecutiveFailures": 1,
      "lastSuccessAt": null,
      "lastFailureAt": null,
      "createdAt": "string",
      "updatedAt": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

**400** – Tenant context missing

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/webhooks" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/webhooks`

Create webhook

Creates a new webhook endpoint. A signing secret (whsec_ prefixed) is auto-generated and returned once.

Requires features: webhooks.manage

**Tags:** Webhooks

**Requires authentication.**

**Features:** webhooks.manage

### Request Body

Content-Type: `application/json`

```json
{
  "name": "string",
  "description": null,
  "url": "https://example.com/resource",
  "subscribedEvents": [
    "string"
  ],
  "httpMethod": "POST",
  "customHeaders": null,
  "deliveryStrategy": "http",
  "strategyConfig": null,
  "maxRetries": 10,
  "timeoutMs": 15000,
  "rateLimitPerMinute": 0,
  "autoDisableThreshold": 100,
  "integrationId": null
}
```

### Responses

**201** – Webhook created

Content-Type: `application/json`

```json
{
  "id": "string",
  "name": "string",
  "url": "string",
  "secret": "string",
  "subscribedEvents": [
    "string"
  ],
  "isActive": true
}
```

**400** – Invalid payload

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/webhooks" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"name\": \"string\",
  \"description\": null,
  \"url\": \"https://example.com/resource\",
  \"subscribedEvents\": [
    \"string\"
  ],
  \"httpMethod\": \"POST\",
  \"customHeaders\": null,
  \"deliveryStrategy\": \"http\",
  \"strategyConfig\": null,
  \"maxRetries\": 10,
  \"timeoutMs\": 15000,
  \"rateLimitPerMinute\": 0,
  \"autoDisableThreshold\": 100,
  \"integrationId\": null
}"
```

## DELETE `/webhooks/{id}`

Delete webhook

Soft-deletes a webhook endpoint.

Requires features: webhooks.manage

**Tags:** Webhooks

**Requires authentication.**

**Features:** webhooks.manage

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

### Responses

**200** – Webhook deleted

Content-Type: `application/json`

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

**404** – Webhook not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/webhooks/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/webhooks/{id}`

Get webhook

Returns webhook configuration, masked secret metadata, and delivery settings.

Requires features: webhooks.view

**Tags:** Webhooks

**Requires authentication.**

**Features:** webhooks.view

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

### Responses

**200** – Webhook detail

Content-Type: `application/json`

```json
{
  "id": "string",
  "name": "string",
  "description": null,
  "url": "string",
  "subscribedEvents": [
    "string"
  ],
  "httpMethod": "string",
  "isActive": true,
  "deliveryStrategy": "string",
  "maxRetries": 1,
  "consecutiveFailures": 1,
  "lastSuccessAt": null,
  "lastFailureAt": null,
  "createdAt": "string",
  "updatedAt": "string",
  "customHeaders": null,
  "strategyConfig": null,
  "timeoutMs": 1,
  "rateLimitPerMinute": 1,
  "autoDisableThreshold": 1,
  "integrationId": null,
  "maskedSecret": "string",
  "previousSecretSetAt": null
}
```

**404** – Webhook not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/webhooks/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/webhooks/{id}`

Update webhook

Updates a single webhook configuration.

Requires features: webhooks.manage

**Tags:** Webhooks

**Requires authentication.**

**Features:** webhooks.manage

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

### Request Body

Content-Type: `application/json`

```json
{
  "description": null,
  "httpMethod": "POST",
  "customHeaders": null,
  "deliveryStrategy": "http",
  "strategyConfig": null,
  "maxRetries": 10,
  "timeoutMs": 15000,
  "rateLimitPerMinute": 0,
  "autoDisableThreshold": 100,
  "integrationId": null
}
```

### Responses

**200** – Webhook updated

Content-Type: `application/json`

```json
{
  "id": "string",
  "name": "string",
  "description": null,
  "url": "string",
  "subscribedEvents": [
    "string"
  ],
  "httpMethod": "string",
  "isActive": true,
  "deliveryStrategy": "string",
  "maxRetries": 1,
  "consecutiveFailures": 1,
  "lastSuccessAt": null,
  "lastFailureAt": null,
  "createdAt": "string",
  "updatedAt": "string",
  "customHeaders": null,
  "strategyConfig": null,
  "timeoutMs": 1,
  "rateLimitPerMinute": 1,
  "autoDisableThreshold": 1,
  "integrationId": null,
  "maskedSecret": "string",
  "previousSecretSetAt": null
}
```

**400** – Invalid payload

Content-Type: `application/json`

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

**404** – Webhook not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/webhooks/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"description\": null,
  \"httpMethod\": \"POST\",
  \"customHeaders\": null,
  \"deliveryStrategy\": \"http\",
  \"strategyConfig\": null,
  \"maxRetries\": 10,
  \"timeoutMs\": 15000,
  \"rateLimitPerMinute\": 0,
  \"autoDisableThreshold\": 100,
  \"integrationId\": null
}"
```

## POST `/webhooks/{id}/rotate-secret`

Rotate secret

Returns the new secret once. Store it immediately; future reads only expose a masked value.

Requires features: webhooks.secrets

**Tags:** Webhooks

**Requires authentication.**

**Features:** webhooks.secrets

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

### Responses

**200** – Secret rotated

Content-Type: `application/json`

```json
{
  "success": true,
  "secret": "string",
  "previousSecretSetAt": null
}
```

**404** – Webhook not found

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/webhooks/00000000-0000-4000-8000-000000000000/rotate-secret" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/webhooks/{id}/test`

Test webhook

Creates a synthetic event payload and delivers it immediately without using the queue.

Requires features: webhooks.test

**Tags:** Webhooks

**Requires authentication.**

**Features:** webhooks.test

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

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Test delivery result

Content-Type: `application/json`

```json
{
  "success": true,
  "delivery": {
    "id": "string",
    "webhookId": "string",
    "eventType": "string",
    "messageId": "string",
    "status": "string",
    "responseStatus": null,
    "errorMessage": null,
    "attemptNumber": 1,
    "maxAttempts": 1,
    "targetUrl": "string",
    "durationMs": null,
    "enqueuedAt": "string",
    "lastAttemptAt": null,
    "deliveredAt": null,
    "createdAt": "string",
    "payload": {},
    "responseBody": null,
    "responseHeaders": null,
    "nextRetryAt": null,
    "updatedAt": "string"
  }
}
```

**400** – Invalid request payload

Content-Type: `application/json`

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

**404** – Webhook not found

Content-Type: `application/json`

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

**409** – Webhook integration disabled

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/webhooks/00000000-0000-4000-8000-000000000000/test" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## GET `/webhooks/deliveries`

List delivery logs

Returns paginated webhook delivery attempts with filtering by webhook, event type, and status.

Requires features: webhooks.view

**Tags:** Webhooks

**Requires authentication.**

**Features:** webhooks.view

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

### Responses

**200** – Delivery log collection

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "webhookId": "string",
      "webhookName": null,
      "eventType": "string",
      "messageId": "string",
      "status": "string",
      "responseStatus": null,
      "errorMessage": null,
      "attemptNumber": 1,
      "maxAttempts": 1,
      "targetUrl": "string",
      "durationMs": null,
      "enqueuedAt": "string",
      "lastAttemptAt": null,
      "deliveredAt": null,
      "createdAt": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

**400** – Tenant context missing

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/webhooks/deliveries?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/webhooks/deliveries/{id}`

Get delivery

Returns a single delivery attempt by ID.

Requires features: webhooks.view

**Tags:** Webhooks

**Requires authentication.**

**Features:** webhooks.view

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

### Responses

**200** – Delivery detail

Content-Type: `application/json`

```json
{
  "id": "string",
  "webhookId": "string",
  "eventType": "string",
  "messageId": "string",
  "status": "string",
  "responseStatus": null,
  "errorMessage": null,
  "attemptNumber": 1,
  "maxAttempts": 1,
  "targetUrl": "string",
  "durationMs": null,
  "enqueuedAt": "string",
  "lastAttemptAt": null,
  "deliveredAt": null,
  "createdAt": "string",
  "payload": {},
  "responseBody": null,
  "responseHeaders": null,
  "nextRetryAt": null,
  "updatedAt": "string"
}
```

**404** – Delivery not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/webhooks/deliveries/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/webhooks/deliveries/{id}/retry`

Retry delivery

Resets retry scheduling fields and enqueues the delivery again.

Requires features: webhooks.manage

**Tags:** Webhooks

**Requires authentication.**

**Features:** webhooks.manage

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

### Responses

**200** – Delivery re-enqueued

Content-Type: `application/json`

```json
{
  "success": true,
  "delivery": {
    "id": "string",
    "webhookId": "string",
    "eventType": "string",
    "messageId": "string",
    "status": "string",
    "responseStatus": null,
    "errorMessage": null,
    "attemptNumber": 1,
    "maxAttempts": 1,
    "targetUrl": "string",
    "durationMs": null,
    "enqueuedAt": "string",
    "lastAttemptAt": null,
    "deliveredAt": null,
    "createdAt": "string",
    "payload": {},
    "responseBody": null,
    "responseHeaders": null,
    "nextRetryAt": null,
    "updatedAt": "string"
  }
}
```

**404** – Delivery not found

Content-Type: `application/json`

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

**409** – Webhook integration disabled

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/webhooks/deliveries/00000000-0000-4000-8000-000000000000/retry" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/webhooks/events`

List webhook events

Returns all declared non-webhook events, sorted by event id.

Requires features: webhooks.view

**Tags:** Webhooks

**Requires authentication.**

**Features:** webhooks.view

### Responses

**200** – Available events

Content-Type: `application/json`

```json
{
  "data": [
    {
      "id": "string",
      "label": "string"
    }
  ],
  "total": 1
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/webhooks/events" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/webhooks/inbound/{endpointId}`

Receive inbound webhook

Endpoint ids currently resolve to registered adapter provider keys.

**Tags:** Webhooks

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

### Responses

**200** – Inbound webhook accepted

Content-Type: `application/json`

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

**400** – Verification failed

Content-Type: `application/json`

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

**404** – Endpoint not found

Content-Type: `application/json`

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

**429** – Rate limit exceeded

Content-Type: `application/json`

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

**503** – Webhook integration disabled

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/webhooks/inbound/string" \
  -H "Accept: application/json"
```

## GET `/webhooks/webhook-deliveries`

List delivery logs

Returns paginated webhook delivery attempts with filtering by webhook, event type, and status.

Requires features: webhooks.view

**Tags:** Webhooks

**Requires authentication.**

**Features:** webhooks.view

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

### Responses

**200** – Delivery log collection

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "webhookId": "string",
      "webhookName": null,
      "eventType": "string",
      "messageId": "string",
      "status": "string",
      "responseStatus": null,
      "errorMessage": null,
      "attemptNumber": 1,
      "maxAttempts": 1,
      "targetUrl": "string",
      "durationMs": null,
      "enqueuedAt": "string",
      "lastAttemptAt": null,
      "deliveredAt": null,
      "createdAt": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

**400** – Tenant context missing

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/webhooks/webhook-deliveries?page=1&pageSize=50" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/webhooks/webhook-deliveries/{id}`

Get delivery

Returns a single delivery attempt by ID.

Requires features: webhooks.view

**Tags:** Webhooks

**Requires authentication.**

**Features:** webhooks.view

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

### Responses

**200** – Delivery detail

Content-Type: `application/json`

```json
{
  "id": "string",
  "webhookId": "string",
  "eventType": "string",
  "messageId": "string",
  "status": "string",
  "responseStatus": null,
  "errorMessage": null,
  "attemptNumber": 1,
  "maxAttempts": 1,
  "targetUrl": "string",
  "durationMs": null,
  "enqueuedAt": "string",
  "lastAttemptAt": null,
  "deliveredAt": null,
  "createdAt": "string",
  "payload": {},
  "responseBody": null,
  "responseHeaders": null,
  "nextRetryAt": null,
  "updatedAt": "string"
}
```

**404** – Delivery not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/webhooks/webhook-deliveries/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/webhooks/webhook-deliveries/{id}/retry`

Retry delivery

Resets retry scheduling fields and enqueues the delivery again.

Requires features: webhooks.manage

**Tags:** Webhooks

**Requires authentication.**

**Features:** webhooks.manage

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

### Responses

**200** – Delivery re-enqueued

Content-Type: `application/json`

```json
{
  "success": true,
  "delivery": {
    "id": "string",
    "webhookId": "string",
    "eventType": "string",
    "messageId": "string",
    "status": "string",
    "responseStatus": null,
    "errorMessage": null,
    "attemptNumber": 1,
    "maxAttempts": 1,
    "targetUrl": "string",
    "durationMs": null,
    "enqueuedAt": "string",
    "lastAttemptAt": null,
    "deliveredAt": null,
    "createdAt": "string",
    "payload": {},
    "responseBody": null,
    "responseHeaders": null,
    "nextRetryAt": null,
    "updatedAt": "string"
  }
}
```

**404** – Delivery not found

Content-Type: `application/json`

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

**409** – Webhook integration disabled

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/webhooks/webhook-deliveries/00000000-0000-4000-8000-000000000000/retry" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## DELETE `/webhooks/webhooks`

Delete webhook

Soft-deletes a webhook endpoint.

Requires features: webhooks.manage

**Tags:** Webhooks

**Requires authentication.**

**Features:** webhooks.manage

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | query | any | Required. Webhook ID to delete |

### Responses

**200** – Deleted

Content-Type: `application/json`

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

**404** – Not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/webhooks/webhooks?id=00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/webhooks/webhooks`

List webhooks

Returns paginated webhooks for the current tenant and organization.

Requires features: webhooks.view

**Tags:** Webhooks

**Requires authentication.**

**Features:** webhooks.view

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

### Responses

**200** – Webhook collection

Content-Type: `application/json`

```json
{
  "items": [
    {
      "id": "string",
      "name": "string",
      "description": null,
      "url": "string",
      "subscribedEvents": [
        "string"
      ],
      "httpMethod": "string",
      "isActive": true,
      "deliveryStrategy": "string",
      "maxRetries": 1,
      "consecutiveFailures": 1,
      "lastSuccessAt": null,
      "lastFailureAt": null,
      "createdAt": "string",
      "updatedAt": "string"
    }
  ],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

**400** – Tenant context missing

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/webhooks/webhooks" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/webhooks/webhooks`

Create webhook

Creates a new webhook endpoint. A signing secret (whsec_ prefixed) is auto-generated and returned once.

Requires features: webhooks.manage

**Tags:** Webhooks

**Requires authentication.**

**Features:** webhooks.manage

### Request Body

Content-Type: `application/json`

```json
{
  "name": "string",
  "description": null,
  "url": "https://example.com/resource",
  "subscribedEvents": [
    "string"
  ],
  "httpMethod": "POST",
  "customHeaders": null,
  "deliveryStrategy": "http",
  "strategyConfig": null,
  "maxRetries": 10,
  "timeoutMs": 15000,
  "rateLimitPerMinute": 0,
  "autoDisableThreshold": 100,
  "integrationId": null
}
```

### Responses

**201** – Webhook created

Content-Type: `application/json`

```json
{
  "id": "string",
  "name": "string",
  "url": "string",
  "secret": "string",
  "subscribedEvents": [
    "string"
  ],
  "isActive": true
}
```

**400** – Invalid payload

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/webhooks/webhooks" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"name\": \"string\",
  \"description\": null,
  \"url\": \"https://example.com/resource\",
  \"subscribedEvents\": [
    \"string\"
  ],
  \"httpMethod\": \"POST\",
  \"customHeaders\": null,
  \"deliveryStrategy\": \"http\",
  \"strategyConfig\": null,
  \"maxRetries\": 10,
  \"timeoutMs\": 15000,
  \"rateLimitPerMinute\": 0,
  \"autoDisableThreshold\": 100,
  \"integrationId\": null
}"
```

## PUT `/webhooks/webhooks`

Update webhook

Updates an existing webhook configuration.

Requires features: webhooks.manage

**Tags:** Webhooks

**Requires authentication.**

**Features:** webhooks.manage

### Request Body

Content-Type: `application/json`

```json
{
  "description": null,
  "httpMethod": "POST",
  "customHeaders": null,
  "deliveryStrategy": "http",
  "strategyConfig": null,
  "maxRetries": 10,
  "timeoutMs": 15000,
  "rateLimitPerMinute": 0,
  "autoDisableThreshold": 100,
  "integrationId": null
}
```

### Responses

**200** – Webhook updated

Content-Type: `application/json`

```json
{
  "id": "string",
  "name": "string",
  "description": null,
  "url": "string",
  "subscribedEvents": [
    "string"
  ],
  "httpMethod": "string",
  "isActive": true,
  "deliveryStrategy": "string",
  "maxRetries": 1,
  "consecutiveFailures": 1,
  "lastSuccessAt": null,
  "lastFailureAt": null,
  "createdAt": "string",
  "updatedAt": "string",
  "customHeaders": null,
  "strategyConfig": null,
  "timeoutMs": 1,
  "rateLimitPerMinute": 1,
  "autoDisableThreshold": 1,
  "integrationId": null
}
```

**400** – Invalid payload

Content-Type: `application/json`

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

**404** – Not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/webhooks/webhooks" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"description\": null,
  \"httpMethod\": \"POST\",
  \"customHeaders\": null,
  \"deliveryStrategy\": \"http\",
  \"strategyConfig\": null,
  \"maxRetries\": 10,
  \"timeoutMs\": 15000,
  \"rateLimitPerMinute\": 0,
  \"autoDisableThreshold\": 100,
  \"integrationId\": null
}"
```

## DELETE `/webhooks/webhooks/{id}`

Delete webhook

Soft-deletes a webhook endpoint.

Requires features: webhooks.manage

**Tags:** Webhooks

**Requires authentication.**

**Features:** webhooks.manage

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

### Responses

**200** – Webhook deleted

Content-Type: `application/json`

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

**404** – Webhook not found

Content-Type: `application/json`

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

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/webhooks/webhooks/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## GET `/webhooks/webhooks/{id}`

Get webhook

Returns webhook configuration, masked secret metadata, and delivery settings.

Requires features: webhooks.view

**Tags:** Webhooks

**Requires authentication.**

**Features:** webhooks.view

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

### Responses

**200** – Webhook detail

Content-Type: `application/json`

```json
{
  "id": "string",
  "name": "string",
  "description": null,
  "url": "string",
  "subscribedEvents": [
    "string"
  ],
  "httpMethod": "string",
  "isActive": true,
  "deliveryStrategy": "string",
  "maxRetries": 1,
  "consecutiveFailures": 1,
  "lastSuccessAt": null,
  "lastFailureAt": null,
  "createdAt": "string",
  "updatedAt": "string",
  "customHeaders": null,
  "strategyConfig": null,
  "timeoutMs": 1,
  "rateLimitPerMinute": 1,
  "autoDisableThreshold": 1,
  "integrationId": null,
  "maskedSecret": "string",
  "previousSecretSetAt": null
}
```

**404** – Webhook not found

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/webhooks/webhooks/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## PUT `/webhooks/webhooks/{id}`

Update webhook

Updates a single webhook configuration.

Requires features: webhooks.manage

**Tags:** Webhooks

**Requires authentication.**

**Features:** webhooks.manage

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

### Request Body

Content-Type: `application/json`

```json
{
  "description": null,
  "httpMethod": "POST",
  "customHeaders": null,
  "deliveryStrategy": "http",
  "strategyConfig": null,
  "maxRetries": 10,
  "timeoutMs": 15000,
  "rateLimitPerMinute": 0,
  "autoDisableThreshold": 100,
  "integrationId": null
}
```

### Responses

**200** – Webhook updated

Content-Type: `application/json`

```json
{
  "id": "string",
  "name": "string",
  "description": null,
  "url": "string",
  "subscribedEvents": [
    "string"
  ],
  "httpMethod": "string",
  "isActive": true,
  "deliveryStrategy": "string",
  "maxRetries": 1,
  "consecutiveFailures": 1,
  "lastSuccessAt": null,
  "lastFailureAt": null,
  "createdAt": "string",
  "updatedAt": "string",
  "customHeaders": null,
  "strategyConfig": null,
  "timeoutMs": 1,
  "rateLimitPerMinute": 1,
  "autoDisableThreshold": 1,
  "integrationId": null,
  "maskedSecret": "string",
  "previousSecretSetAt": null
}
```

**400** – Invalid payload

Content-Type: `application/json`

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

**404** – Webhook not found

Content-Type: `application/json`

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

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/webhooks/webhooks/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{
  \"description\": null,
  \"httpMethod\": \"POST\",
  \"customHeaders\": null,
  \"deliveryStrategy\": \"http\",
  \"strategyConfig\": null,
  \"maxRetries\": 10,
  \"timeoutMs\": 15000,
  \"rateLimitPerMinute\": 0,
  \"autoDisableThreshold\": 100,
  \"integrationId\": null
}"
```

## POST `/webhooks/webhooks/{id}/rotate-secret`

Rotate secret

Returns the new secret once. Store it immediately; future reads only expose a masked value.

Requires features: webhooks.secrets

**Tags:** Webhooks

**Requires authentication.**

**Features:** webhooks.secrets

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

### Responses

**200** – Secret rotated

Content-Type: `application/json`

```json
{
  "success": true,
  "secret": "string",
  "previousSecretSetAt": null
}
```

**404** – Webhook not found

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/webhooks/webhooks/00000000-0000-4000-8000-000000000000/rotate-secret" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>"
```

## POST `/webhooks/webhooks/{id}/test`

Test webhook

Creates a synthetic event payload and delivers it immediately without using the queue.

Requires features: webhooks.test

**Tags:** Webhooks

**Requires authentication.**

**Features:** webhooks.test

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

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Test delivery result

Content-Type: `application/json`

```json
{
  "success": true,
  "delivery": {
    "id": "string",
    "webhookId": "string",
    "eventType": "string",
    "messageId": "string",
    "status": "string",
    "responseStatus": null,
    "errorMessage": null,
    "attemptNumber": 1,
    "maxAttempts": 1,
    "targetUrl": "string",
    "durationMs": null,
    "enqueuedAt": "string",
    "lastAttemptAt": null,
    "deliveredAt": null,
    "createdAt": "string",
    "payload": {},
    "responseBody": null,
    "responseHeaders": null,
    "nextRetryAt": null,
    "updatedAt": "string"
  }
}
```

**400** – Invalid request payload

Content-Type: `application/json`

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

**404** – Webhook not found

Content-Type: `application/json`

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

**409** – Webhook integration disabled

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/webhooks/webhooks/00000000-0000-4000-8000-000000000000/test" \
  -H "Accept: application/json" \
  -H "authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## GET `/workflows/definitions`

List workflow definitions

Get a list of workflow definitions with optional filters. Supports pagination and search.

**Tags:** Workflows

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| workflowId | query | any | Required |
| enabled | query | any | Optional |
| search | query | any | Optional |
| limit | query | any | Optional |
| offset | query | any | Optional |

### Responses

**200** – List of workflow definitions with pagination

Content-Type: `application/json`

```json
{
  "data": [
    {
      "id": "123e4567-e89b-12d3-a456-426614174000",
      "workflowId": "checkout-flow",
      "workflowName": "Checkout Flow",
      "description": "Complete checkout workflow for processing orders",
      "version": 1,
      "definition": {
        "steps": [
          {
            "stepId": "start",
            "stepName": "Start",
            "stepType": "START"
          },
          {
            "stepId": "validate-cart",
            "stepName": "Validate Cart",
            "stepType": "AUTOMATED"
          },
          {
            "stepId": "end",
            "stepName": "End",
            "stepType": "END"
          }
        ],
        "transitions": [
          {
            "transitionId": "start-to-validate",
            "fromStepId": "start",
            "toStepId": "validate-cart",
            "trigger": "auto"
          },
          {
            "transitionId": "validate-to-end",
            "fromStepId": "validate-cart",
            "toStepId": "end",
            "trigger": "auto"
          }
        ]
      },
      "enabled": true,
      "tenantId": "123e4567-e89b-12d3-a456-426614174001",
      "organizationId": "123e4567-e89b-12d3-a456-426614174002",
      "createdAt": "2025-12-08T10:00:00.000Z",
      "updatedAt": "2025-12-08T10:00:00.000Z"
    }
  ],
  "pagination": {
    "total": 1,
    "limit": 50,
    "offset": 0,
    "hasMore": false
  }
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/workflows/definitions?workflowId=string&limit=50&offset=0" \
  -H "Accept: application/json"
```

## POST `/workflows/definitions`

Create workflow definition

Create a new workflow definition. The definition must include at least START and END steps with at least one transition connecting them.

**Tags:** Workflows

### Request Body

Content-Type: `application/json`

```json
{
  "workflowId": "checkout-flow",
  "workflowName": "Checkout Flow",
  "description": "Complete checkout workflow for processing orders",
  "version": 1,
  "definition": {
    "steps": [
      {
        "stepId": "start",
        "stepName": "Start",
        "stepType": "START"
      },
      {
        "stepId": "validate-cart",
        "stepName": "Validate Cart",
        "stepType": "AUTOMATED",
        "description": "Validate cart items and check inventory"
      },
      {
        "stepId": "payment",
        "stepName": "Process Payment",
        "stepType": "AUTOMATED",
        "description": "Charge payment method",
        "retryPolicy": {
          "maxAttempts": 3,
          "backoffMs": 1000
        }
      },
      {
        "stepId": "end",
        "stepName": "End",
        "stepType": "END"
      }
    ],
    "transitions": [
      {
        "transitionId": "start-to-validate",
        "fromStepId": "start",
        "toStepId": "validate-cart",
        "trigger": "auto"
      },
      {
        "transitionId": "validate-to-payment",
        "fromStepId": "validate-cart",
        "toStepId": "payment",
        "trigger": "auto"
      },
      {
        "transitionId": "payment-to-end",
        "fromStepId": "payment",
        "toStepId": "end",
        "trigger": "auto",
        "activities": [
          {
            "activityName": "Send Order Confirmation",
            "activityType": "SEND_EMAIL",
            "config": {
              "to": "{{context.customerEmail}}",
              "subject": "Order Confirmation #{{context.orderId}}",
              "template": "order_confirmation"
            }
          }
        ]
      }
    ]
  },
  "enabled": true
}
```

### Responses

**201** – Workflow definition created successfully

Content-Type: `application/json`

```json
{
  "data": {
    "id": "123e4567-e89b-12d3-a456-426614174000",
    "workflowId": "checkout-flow",
    "workflowName": "Checkout Flow",
    "description": "Complete checkout workflow for processing orders",
    "version": 1,
    "definition": {
      "steps": [
        {
          "stepId": "start",
          "stepName": "Start",
          "stepType": "START"
        },
        {
          "stepId": "validate-cart",
          "stepName": "Validate Cart",
          "stepType": "AUTOMATED"
        },
        {
          "stepId": "payment",
          "stepName": "Process Payment",
          "stepType": "AUTOMATED"
        },
        {
          "stepId": "end",
          "stepName": "End",
          "stepType": "END"
        }
      ],
      "transitions": [
        {
          "transitionId": "start-to-validate",
          "fromStepId": "start",
          "toStepId": "validate-cart",
          "trigger": "auto"
        },
        {
          "transitionId": "validate-to-payment",
          "fromStepId": "validate-cart",
          "toStepId": "payment",
          "trigger": "auto"
        },
        {
          "transitionId": "payment-to-end",
          "fromStepId": "payment",
          "toStepId": "end",
          "trigger": "auto"
        }
      ]
    },
    "enabled": true,
    "tenantId": "123e4567-e89b-12d3-a456-426614174001",
    "organizationId": "123e4567-e89b-12d3-a456-426614174002",
    "createdAt": "2025-12-08T10:00:00.000Z",
    "updatedAt": "2025-12-08T10:00:00.000Z"
  },
  "message": "Workflow definition created successfully"
}
```

**400** – Validation error - invalid workflow structure

Content-Type: `application/json`

```json
{
  "error": "Validation failed",
  "details": [
    {
      "code": "invalid_type",
      "message": "Workflow must have at least START and END steps",
      "path": [
        "definition",
        "steps"
      ]
    }
  ]
}
```

**409** – Conflict - workflow with same ID and version already exists

Content-Type: `application/json`

```json
{
  "error": "Workflow definition with ID \"checkout-flow\" and version 1 already exists"
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/workflows/definitions" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"workflowId\": \"string\",
  \"workflowName\": \"string\",
  \"description\": null,
  \"version\": 1,
  \"definition\": {
    \"steps\": [
      {
        \"stepId\": \"string\",
        \"stepName\": \"string\",
        \"stepType\": \"START\"
      }
    ],
    \"transitions\": [
      {
        \"transitionId\": \"string\",
        \"fromStepId\": \"string\",
        \"toStepId\": \"string\",
        \"trigger\": \"auto\",
        \"continueOnActivityFailure\": true,
        \"priority\": 0
      }
    ]
  },
  \"metadata\": null,
  \"enabled\": true
}"
```

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

Delete workflow definition

Soft delete a workflow definition. Cannot be deleted if there are active workflow instances (RUNNING or WAITING status) using this definition.

**Tags:** Workflows

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

### Responses

**200** – Workflow definition deleted successfully

Content-Type: `application/json`

```json
{
  "message": "Workflow definition deleted successfully"
}
```

**404** – Workflow definition not found

Content-Type: `application/json`

```json
{
  "error": "Workflow definition not found"
}
```

**409** – Cannot delete - active workflow instances exist

Content-Type: `application/json`

```json
{
  "error": "Cannot delete workflow definition with 3 active instance(s)"
}
```

### Example

```bash
curl -X DELETE "https://crmprod.erp.sobota.myopenmercato.com/workflows/definitions/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json"
```

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

Get workflow definition

Get a single workflow definition by ID. Returns the complete workflow structure including steps and transitions (with embedded activities).

**Tags:** Workflows

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

### Responses

**200** – Workflow definition found

Content-Type: `application/json`

```json
{
  "data": {
    "id": "123e4567-e89b-12d3-a456-426614174000",
    "workflowId": "checkout-flow",
    "workflowName": "Checkout Flow",
    "description": "Complete checkout workflow for processing orders",
    "version": 1,
    "definition": {
      "steps": [
        {
          "stepId": "start",
          "stepName": "Start",
          "stepType": "START"
        },
        {
          "stepId": "validate-cart",
          "stepName": "Validate Cart",
          "stepType": "AUTOMATED",
          "description": "Validate cart items and check inventory"
        },
        {
          "stepId": "payment",
          "stepName": "Process Payment",
          "stepType": "AUTOMATED",
          "description": "Charge payment method",
          "retryPolicy": {
            "maxAttempts": 3,
            "backoffMs": 1000
          }
        },
        {
          "stepId": "end",
          "stepName": "End",
          "stepType": "END"
        }
      ],
      "transitions": [
        {
          "transitionId": "start-to-validate",
          "fromStepId": "start",
          "toStepId": "validate-cart",
          "trigger": "auto"
        },
        {
          "transitionId": "validate-to-payment",
          "fromStepId": "validate-cart",
          "toStepId": "payment",
          "trigger": "auto"
        },
        {
          "transitionId": "payment-to-end",
          "fromStepId": "payment",
          "toStepId": "end",
          "trigger": "auto",
          "activities": [
            {
              "activityName": "Send Order Confirmation",
              "activityType": "SEND_EMAIL",
              "config": {
                "to": "{{context.customerEmail}}",
                "subject": "Order Confirmation #{{context.orderId}}",
                "template": "order_confirmation"
              }
            }
          ]
        }
      ]
    },
    "enabled": true,
    "tenantId": "123e4567-e89b-12d3-a456-426614174001",
    "organizationId": "123e4567-e89b-12d3-a456-426614174002",
    "createdAt": "2025-12-08T10:00:00.000Z",
    "updatedAt": "2025-12-08T10:00:00.000Z"
  }
}
```

**404** – Workflow definition not found

Content-Type: `application/json`

```json
{
  "error": "Workflow definition not found"
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/workflows/definitions/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json"
```

## PUT `/workflows/definitions/{id}`

Update workflow definition

Update an existing workflow definition. Supports partial updates - only provided fields will be updated.

**Tags:** Workflows

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

### Request Body

Content-Type: `application/json`

```json
{
  "definition": {
    "steps": [
      {
        "stepId": "start",
        "stepName": "Start",
        "stepType": "START"
      },
      {
        "stepId": "validate-cart",
        "stepName": "Validate Cart",
        "stepType": "AUTOMATED"
      },
      {
        "stepId": "payment",
        "stepName": "Process Payment",
        "stepType": "AUTOMATED"
      },
      {
        "stepId": "confirmation",
        "stepName": "Order Confirmation",
        "stepType": "AUTOMATED"
      },
      {
        "stepId": "end",
        "stepName": "End",
        "stepType": "END"
      }
    ],
    "transitions": [
      {
        "transitionId": "start-to-validate",
        "fromStepId": "start",
        "toStepId": "validate-cart",
        "trigger": "auto"
      },
      {
        "transitionId": "validate-to-payment",
        "fromStepId": "validate-cart",
        "toStepId": "payment",
        "trigger": "auto"
      },
      {
        "transitionId": "payment-to-confirmation",
        "fromStepId": "payment",
        "toStepId": "confirmation",
        "trigger": "auto"
      },
      {
        "transitionId": "confirmation-to-end",
        "fromStepId": "confirmation",
        "toStepId": "end",
        "trigger": "auto"
      }
    ]
  },
  "enabled": true
}
```

### Responses

**200** – Workflow definition updated successfully

Content-Type: `application/json`

```json
{
  "data": {
    "id": "123e4567-e89b-12d3-a456-426614174000",
    "workflowId": "checkout-flow",
    "workflowName": "Checkout Flow",
    "description": "Complete checkout workflow for processing orders",
    "version": 1,
    "definition": {
      "steps": [
        {
          "stepId": "start",
          "stepName": "Start",
          "stepType": "START"
        },
        {
          "stepId": "validate-cart",
          "stepName": "Validate Cart",
          "stepType": "AUTOMATED"
        },
        {
          "stepId": "payment",
          "stepName": "Process Payment",
          "stepType": "AUTOMATED"
        },
        {
          "stepId": "confirmation",
          "stepName": "Order Confirmation",
          "stepType": "AUTOMATED"
        },
        {
          "stepId": "end",
          "stepName": "End",
          "stepType": "END"
        }
      ],
      "transitions": [
        {
          "transitionId": "start-to-validate",
          "fromStepId": "start",
          "toStepId": "validate-cart",
          "trigger": "auto"
        },
        {
          "transitionId": "validate-to-payment",
          "fromStepId": "validate-cart",
          "toStepId": "payment",
          "trigger": "auto"
        },
        {
          "transitionId": "payment-to-confirmation",
          "fromStepId": "payment",
          "toStepId": "confirmation",
          "trigger": "auto"
        },
        {
          "transitionId": "confirmation-to-end",
          "fromStepId": "confirmation",
          "toStepId": "end",
          "trigger": "auto"
        }
      ]
    },
    "enabled": true,
    "tenantId": "123e4567-e89b-12d3-a456-426614174001",
    "organizationId": "123e4567-e89b-12d3-a456-426614174002",
    "createdAt": "2025-12-08T10:00:00.000Z",
    "updatedAt": "2025-12-08T11:30:00.000Z"
  },
  "message": "Workflow definition updated successfully"
}
```

**400** – Validation error

Content-Type: `application/json`

```json
{
  "error": "Validation failed",
  "details": [
    {
      "code": "invalid_type",
      "message": "Expected object, received string",
      "path": [
        "definition"
      ]
    }
  ]
}
```

**404** – Workflow definition not found

Content-Type: `application/json`

```json
{
  "error": "Workflow definition not found"
}
```

### Example

```bash
curl -X PUT "https://crmprod.erp.sobota.myopenmercato.com/workflows/definitions/00000000-0000-4000-8000-000000000000" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## GET `/workflows/events`

List all workflow events

Get a paginated list of all workflow events with filtering options

**Tags:** Workflows

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| page | query | any | Optional |
| pageSize | query | any | Optional |
| eventType | query | any | Optional |
| workflowInstanceId | query | any | Optional |
| userId | query | any | Optional |
| occurredAtFrom | query | any | Optional |
| occurredAtTo | query | any | Optional |
| sortField | query | any | Optional |
| sortDir | query | any | Optional |

### Responses

**200** – List of workflow events

Content-Type: `application/json`

```json
{
  "items": [],
  "total": 1,
  "page": 1,
  "pageSize": 1,
  "totalPages": 1
}
```

**401** – Unauthorized

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**500** – Internal server error

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/workflows/events?page=1&pageSize=50&sortField=occurredAt&sortDir=desc" \
  -H "Accept: application/json"
```

## GET `/workflows/events/{id}`

Get workflow event by ID

Get detailed information about a specific workflow event

**Tags:** Workflows

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

### Responses

**200** – Workflow event details

Content-Type: `application/json`

```json
{
  "id": "string",
  "workflowInstanceId": "string",
  "stepInstanceId": null,
  "eventType": "string",
  "occurredAt": "string",
  "userId": null,
  "workflowInstance": null
}
```

**401** – Unauthorized

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**404** – Workflow event 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://crmprod.erp.sobota.myopenmercato.com/workflows/events/:id" \
  -H "Accept: application/json"
```

## GET `/workflows/instances`

List workflow instances

Get a list of workflow instances with optional filters. Supports pagination and filtering by status, workflowId, correlationKey, etc.

**Tags:** Workflows

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| workflowId | query | any | Optional |
| status | query | any | Optional |
| correlationKey | query | any | Optional |
| entityType | query | any | Optional |
| entityId | query | any | Optional |
| limit | query | any | Optional |
| offset | query | any | Optional |

### Responses

**200** – List of workflow instances

Content-Type: `application/json`

```json
{
  "data": [],
  "pagination": {
    "total": 1,
    "limit": 1,
    "offset": 1,
    "hasMore": true
  }
}
```

**401** – Unauthorized

Content-Type: `application/json`

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

**500** – Internal server error

Content-Type: `application/json`

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

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/workflows/instances?limit=50&offset=0" \
  -H "Accept: application/json"
```

## POST `/workflows/instances`

Start workflow instance

Start a new workflow instance from a workflow definition. The workflow will execute immediately.

**Tags:** Workflows

### Request Body

Content-Type: `application/json`

```json
{
  "workflowId": "string"
}
```

### Responses

**201** – Workflow started successfully

Content-Type: `application/json`

```json
{
  "data": {},
  "message": "string"
}
```

**400** – Bad request - Validation failed or definition disabled/invalid

Content-Type: `application/json`

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

**401** – Unauthorized

Content-Type: `application/json`

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

**403** – Forbidden - Insufficient permissions

Content-Type: `application/json`

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

**404** – Workflow definition not found

Content-Type: `application/json`

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

**500** – Internal server error

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/workflows/instances" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"workflowId\": \"string\"
}"
```

## GET `/workflows/instances/{id}`

Get workflow instance

Get detailed information about a specific workflow instance including current state, context, and execution status.

**Tags:** Workflows

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

### Responses

**200** – Workflow instance details

Content-Type: `application/json`

```json
{}
```

**401** – Unauthorized

Content-Type: `application/json`

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

**404** – Workflow instance 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://crmprod.erp.sobota.myopenmercato.com/workflows/instances/:id" \
  -H "Accept: application/json"
```

## POST `/workflows/instances/{id}/advance`

Manually advance workflow to next step

Manually advance a workflow instance to the next step. Useful for manual progression, step-by-step testing, user-triggered transitions, and approval flows. Validates transitions and auto-progresses if possible.

**Tags:** Workflows

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

### Request Body

Content-Type: `application/json`

```json
{}
```

### Responses

**200** – Workflow advanced successfully

Content-Type: `application/json`

```json
{
  "data": {
    "instance": {
      "id": "00000000-0000-4000-8000-000000000000",
      "status": "string",
      "currentStepId": null,
      "previousStepId": null,
      "transitionFired": null
    }
  },
  "message": "string"
}
```

**400** – Invalid request, no valid transitions, or workflow already completed/cancelled/failed

Content-Type: `application/json`

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

**401** – Unauthorized

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**404** – Workflow instance not found

Content-Type: `application/json`

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

**500** – Internal server error

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/workflows/instances/:id/advance" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{}"
```

## POST `/workflows/instances/{id}/cancel`

Cancel workflow instance

Cancel a running or paused workflow instance. The workflow will be marked as CANCELLED and will not execute further.

**Tags:** Workflows

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

### Responses

**200** – Workflow cancelled successfully

Content-Type: `application/json`

```json
{
  "message": "string"
}
```

**400** – Bad request - Workflow cannot be cancelled in current status

Content-Type: `application/json`

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

**401** – Unauthorized

Content-Type: `application/json`

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

**403** – Forbidden - Insufficient permissions

Content-Type: `application/json`

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

**404** – Workflow instance not found

Content-Type: `application/json`

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

**500** – Internal server error

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/workflows/instances/:id/cancel" \
  -H "Accept: application/json"
```

## GET `/workflows/instances/{id}/events`

Get workflow instance events

Get a chronological list of events for a workflow instance. Events track all state changes, transitions, and activities.

**Tags:** Workflows

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

### Responses

**200** – List of workflow events

Content-Type: `application/json`

```json
{
  "data": [],
  "pagination": {
    "total": 1,
    "limit": 1,
    "offset": 1,
    "hasMore": true
  }
}
```

**401** – Unauthorized

Content-Type: `application/json`

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

**404** – Workflow instance 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://crmprod.erp.sobota.myopenmercato.com/workflows/instances/:id/events?limit=100&offset=0" \
  -H "Accept: application/json"
```

## POST `/workflows/instances/{id}/retry`

Retry failed workflow instance

Retry a failed workflow instance from its current step. The workflow will be reset to RUNNING status and execution will continue.

**Tags:** Workflows

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

### Responses

**200** – Workflow retry initiated successfully

Content-Type: `application/json`

```json
{
  "data": {},
  "message": "string"
}
```

**400** – Bad request - Workflow cannot be retried in current status or execution error

Content-Type: `application/json`

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

**401** – Unauthorized

Content-Type: `application/json`

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

**403** – Forbidden - Insufficient permissions

Content-Type: `application/json`

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

**404** – Workflow instance not found

Content-Type: `application/json`

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

**500** – Internal server error

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/workflows/instances/:id/retry" \
  -H "Accept: application/json"
```

## POST `/workflows/instances/{id}/signal`

Send signal to specific workflow

Sends a signal to a specific workflow instance waiting for a signal. The workflow must be in PAUSED status and waiting for the specified signal.

**Tags:** Workflows

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

### Request Body

Content-Type: `application/json`

```json
{
  "signalName": "string"
}
```

### Responses

**200** – Signal sent successfully

Content-Type: `application/json`

```json
{
  "success": true,
  "message": "string"
}
```

**400** – Invalid request body or signal name mismatch

Content-Type: `application/json`

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

**401** – Unauthorized

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**404** – Instance or definition not found

Content-Type: `application/json`

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

**409** – Workflow not paused or not waiting for signal

Content-Type: `application/json`

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

**500** – Internal server error or transition failed

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/workflows/instances/:id/signal" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"signalName\": \"string\"
}"
```

## POST `/workflows/instances/validate-start`

Validate if workflow can be started

Evaluates pre-conditions defined on the START step and returns validation errors with localized messages if any fail. Returns canStart: true/false with details.

**Tags:** Workflows

### Request Body

Content-Type: `application/json`

```json
{
  "workflowId": "string"
}
```

### Responses

**200** – Validation result (canStart, errors, validatedRules)

Content-Type: `application/json`

```json
{
  "canStart": true,
  "workflowId": "string"
}
```

**400** – Invalid request body or missing context

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
{
  "error": "string"
}
```

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/workflows/instances/validate-start" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"workflowId\": \"string\"
}"
```

## POST `/workflows/signals`

Send signal to workflows by correlation key

Sends a signal to all workflow instances waiting for the specified signal that match the correlation key. Returns the count of workflows that received the signal.

**Tags:** Workflows

### Request Body

Content-Type: `application/json`

```json
{
  "correlationKey": "string",
  "signalName": "string"
}
```

### Responses

**200** – Signal sent to matching workflows

Content-Type: `application/json`

```json
{
  "success": true,
  "message": "string",
  "count": 1
}
```

**400** – Missing tenant or organization context

Content-Type: `application/json`

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

**401** – Unauthorized

Content-Type: `application/json`

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

**403** – Insufficient permissions

Content-Type: `application/json`

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

**500** – Internal server error

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/workflows/signals" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"correlationKey\": \"string\",
  \"signalName\": \"string\"
}"
```

## GET `/workflows/tasks`

List user tasks

Returns paginated list of user tasks with optional filtering by status, assignee, workflow instance, overdue, and myTasks flags.

**Tags:** Workflows

### Parameters
| Name | Location | Type | Description |
| --- | --- | --- | --- |
| status | query | any | Optional. Filter by status (comma-separated for multiple: PENDING,IN_PROGRESS,COMPLETED,CANCELLED,ESCALATED) |
| assignedTo | query | any | Optional. Filter by assigned user ID |
| workflowInstanceId | query | any | Optional. Filter by workflow instance ID |
| overdue | query | any | Optional. Filter overdue tasks (true/false) |
| myTasks | query | any | Optional. Show only tasks assigned to or claimable by current user |
| limit | query | any | Optional. Number of results (max 100) |
| offset | query | any | Optional. Pagination offset |

### Responses

**200** – User tasks list with pagination

Content-Type: `application/json`

```json
{
  "data": [
    {
      "id": "00000000-0000-4000-8000-000000000000",
      "workflowInstanceId": "00000000-0000-4000-8000-000000000000",
      "stepInstanceId": "00000000-0000-4000-8000-000000000000",
      "taskName": "string",
      "description": null,
      "status": "PENDING",
      "formSchema": null,
      "formData": null,
      "assignedTo": null,
      "assignedToRoles": null,
      "claimedBy": null,
      "claimedAt": null,
      "dueDate": null,
      "escalatedAt": null,
      "escalatedTo": null,
      "completedBy": null,
      "completedAt": null,
      "tenantId": "00000000-0000-4000-8000-000000000000",
      "organizationId": "00000000-0000-4000-8000-000000000000",
      "createdAt": "string",
      "updatedAt": "string"
    }
  ],
  "pagination": {
    "total": 1,
    "limit": 1,
    "offset": 1,
    "hasMore": true
  }
}
```

**400** – Invalid query parameters or missing tenant context

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
{
  "error": "string"
}
```

### Example

```bash
curl -X GET "https://crmprod.erp.sobota.myopenmercato.com/workflows/tasks?limit=50&offset=0" \
  -H "Accept: application/json"
```

## GET `/workflows/tasks/{id}`

Get task details

Returns complete details of a user task by ID.

**Tags:** Workflows

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

### Responses

**200** – User task details

Content-Type: `application/json`

```json
{
  "data": {
    "id": "00000000-0000-4000-8000-000000000000",
    "workflowInstanceId": "00000000-0000-4000-8000-000000000000",
    "stepInstanceId": "00000000-0000-4000-8000-000000000000",
    "taskName": "string",
    "description": null,
    "status": "PENDING",
    "formSchema": null,
    "formData": null,
    "assignedTo": null,
    "assignedToRoles": null,
    "claimedBy": null,
    "claimedAt": null,
    "dueDate": null,
    "escalatedAt": null,
    "escalatedTo": null,
    "completedBy": null,
    "completedAt": null,
    "tenantId": "00000000-0000-4000-8000-000000000000",
    "organizationId": "00000000-0000-4000-8000-000000000000",
    "createdAt": "string",
    "updatedAt": "string"
  }
}
```

**400** – Missing tenant or organization context

Content-Type: `application/json`

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

**401** – Unauthorized

Content-Type: `application/json`

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

**404** – Task 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://crmprod.erp.sobota.myopenmercato.com/workflows/tasks/:id" \
  -H "Accept: application/json"
```

## POST `/workflows/tasks/{id}/claim`

Claim a task from role queue

Allows a user to claim a task assigned to their role(s). Once claimed, the task moves to IN_PROGRESS status and is assigned to the claiming user.

**Tags:** Workflows

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

### Responses

**200** – Task claimed successfully

Content-Type: `application/json`

```json
{
  "data": {
    "id": "00000000-0000-4000-8000-000000000000",
    "workflowInstanceId": "00000000-0000-4000-8000-000000000000",
    "stepInstanceId": "00000000-0000-4000-8000-000000000000",
    "taskName": "string",
    "description": null,
    "status": "PENDING",
    "formSchema": null,
    "formData": null,
    "assignedTo": null,
    "assignedToRoles": null,
    "claimedBy": null,
    "claimedAt": null,
    "dueDate": null,
    "escalatedAt": null,
    "escalatedTo": null,
    "completedBy": null,
    "completedAt": null,
    "tenantId": "00000000-0000-4000-8000-000000000000",
    "organizationId": "00000000-0000-4000-8000-000000000000",
    "createdAt": "string",
    "updatedAt": "string"
  },
  "message": "string"
}
```

**400** – Missing tenant or organization context

Content-Type: `application/json`

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

**401** – Unauthorized

Content-Type: `application/json`

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

**404** – Task not found

Content-Type: `application/json`

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

**409** – Task already claimed

Content-Type: `application/json`

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

**500** – Internal server error

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/workflows/tasks/:id/claim" \
  -H "Accept: application/json"
```

## POST `/workflows/tasks/{id}/complete`

Complete a task with form data

Validates form data against task schema, updates task with completion data, merges form data into workflow context, and resumes workflow execution.

**Tags:** Workflows

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

### Request Body

Content-Type: `application/json`

```json
{
  "formData": {}
}
```

### Responses

**200** – Task completed successfully

Content-Type: `application/json`

```json
{
  "data": {
    "id": "00000000-0000-4000-8000-000000000000",
    "workflowInstanceId": "00000000-0000-4000-8000-000000000000",
    "stepInstanceId": "00000000-0000-4000-8000-000000000000",
    "taskName": "string",
    "description": null,
    "status": "PENDING",
    "formSchema": null,
    "formData": null,
    "assignedTo": null,
    "assignedToRoles": null,
    "claimedBy": null,
    "claimedAt": null,
    "dueDate": null,
    "escalatedAt": null,
    "escalatedTo": null,
    "completedBy": null,
    "completedAt": null,
    "tenantId": "00000000-0000-4000-8000-000000000000",
    "organizationId": "00000000-0000-4000-8000-000000000000",
    "createdAt": "string",
    "updatedAt": "string"
  },
  "message": "string"
}
```

**400** – Invalid request body, validation failed, or missing context

Content-Type: `application/json`

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

**401** – Unauthorized

Content-Type: `application/json`

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

**404** – Task not found

Content-Type: `application/json`

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

**409** – Task already completed

Content-Type: `application/json`

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

**500** – Internal server error

Content-Type: `application/json`

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

### Example

```bash
curl -X POST "https://crmprod.erp.sobota.myopenmercato.com/workflows/tasks/:id/complete" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{
  \"formData\": {}
}"
```