{
  "openapi": "3.0.4",
  "info": {
    "title": "Sodium API",
    "description": "A comprehensive API for Sodium Practice Management",
    "version": "v1"
  },
  "paths": {
    "/tenants/{tenant}/accounting/customers": {
      "get": {
        "tags": [
          "Accounting"
        ],
        "summary": "List Customers",
        "description": "Lists all customers in the accounting platform. The platform is the ThirdPartyConnection.Code set in Tenant.AccountingConnectionCode ",
        "operationId": "GetAccountingCustomers",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CustomerDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "502": {
            "description": "Bad Gateway",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Accounting"
        ],
        "summary": "Create Customer",
        "description": "Creates as new AccountingCustomer via the ThirdPartyConnection set as Tenant.AccountingConnectionCode",
        "operationId": "CreateAccountingCustomer",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCustomerRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "502": {
            "description": "Bad Gateway",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/tenants/{tenant}/accounting/customers/{customerId}": {
      "get": {
        "tags": [
          "Accounting"
        ],
        "summary": "Get Customer",
        "description": "Gets the AccountingCustomer from the ThirdPartyConnection set as Tenant.AccountingConnectionCode",
        "operationId": "GetAccountingCustomerById",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "customerId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "502": {
            "description": "Bad Gateway",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/tenants/{tenant}/accounting/customers/{customerId}/invoices": {
      "get": {
        "tags": [
          "Accounting"
        ],
        "summary": "Get Invoices for Customer",
        "description": "Gets all invoices for a specific customer from the ThirdPartyConnection set as Tenant.AccountingConnectionCode",
        "operationId": "GetInvoicesByCustomer",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "customerId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "502": {
            "description": "Bad Gateway",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/tenants/{tenant}/accounting/invoices/{invoiceId}/pdf": {
      "get": {
        "tags": [
          "Accounting"
        ],
        "summary": "Download Invoice PDF",
        "description": "Downloads the PDF for an invoice from the accounting platform. Only available when IsPdfAvailable is true on the invoice. Use the optional 'disposition' parameter: 'attachment' (default) prompts a file download, 'inline' displays the PDF in the browser.",
        "operationId": "GetInvoicePdf",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "disposition",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "invoiceId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/accounting/nominalcodes": {
      "get": {
        "tags": [
          "Accounting"
        ],
        "summary": "List Nominal Codes",
        "description": "Lists chart-of-accounts / nominal codes from the connected accounting platform. Returns 501 if the platform does not support this feature.",
        "operationId": "GetNominalCodes",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/NominalCode"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "501": {
            "description": "Not Implemented"
          }
        }
      }
    },
    "/tenants/{tenant}/ai/settings": {
      "get": {
        "tags": [
          "AI"
        ],
        "summary": "Get AI Settings",
        "description": "Returns the AI settings for the specified tenant",
        "operationId": "GetAiSettings",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiSettingsDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "put": {
        "tags": [
          "AI"
        ],
        "summary": "Update AI Settings",
        "description": "Updates the AI settings for the specified tenant",
        "operationId": "UpdateAiSettings",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateAiSettingsRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiSettingsDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/ai/generate": {
      "post": {
        "tags": [
          "AI"
        ],
        "summary": "Generate Content",
        "description": "Generates content using AI based on the activity type and key provided. Supports various content types like service descriptions, proposals, workflows, pricing factors, etc.",
        "operationId": "GenerateAiContent",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AiGenerationRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OpenRouterResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          },
          "500": {
            "description": "Internal Server Error"
          }
        }
      }
    },
    "/tenants/{tenant}/ai/usage/summary": {
      "get": {
        "tags": [
          "AI"
        ],
        "summary": "Get Usage Summary",
        "description": "Retrieves AI token usage summary for a date range",
        "operationId": "GetAiUsageSummary",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "startDate",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "x-order": 100
          },
          {
            "name": "endDate",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "x-order": 101
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiUsageSummaryDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/aml/clients": {
      "get": {
        "tags": [
          "AML"
        ],
        "summary": "List AML Clients",
        "description": "Lists clients (accounts) from the AML platform with pagination. When a search term is provided, searches across client name, reference, and contact details.",
        "operationId": "GetAmlClients",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/AmlClientSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search across AML client name, reference, or contact details (minimum 3 characters)",
            "schema": {
              "type": "string",
              "example": "acme"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AmlClientDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "AML"
        ],
        "summary": "Create AML Client",
        "description": "Creates a new client (account) in the AML platform. The platform is the ThirdPartyConnection.Code set in Tenant.AmlConnectionCode",
        "operationId": "CreateAmlClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAmlClientRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AmlClientDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/aml/clients/{clientId}": {
      "get": {
        "tags": [
          "AML"
        ],
        "summary": "Get AML Client",
        "description": "Gets a specific client (account) from the AML platform by ID",
        "operationId": "GetAmlClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "clientId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AmlClientDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/aml/clients/{clientId}/risk-assessments": {
      "get": {
        "tags": [
          "AML"
        ],
        "summary": "Get AML Risk Assessments",
        "description": "Gets the risk assessments for a specific AML client from the AML platform",
        "operationId": "GetAmlRiskAssessments",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "clientId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/AmlClientSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AmlRiskAssessmentDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "AML"
        ],
        "summary": "Start AML Risk Assessment",
        "description": "Starts a new risk assessment for a specific AML client in the AML platform. Optionally attach a questionnaire template.",
        "operationId": "StartAmlRiskAssessment",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "clientId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateRiskAssessmentRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AmlRiskAssessmentDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/aml/risk-assessment-templates": {
      "get": {
        "tags": [
          "AML"
        ],
        "summary": "List AML Risk Assessment Templates",
        "description": "Lists questionnaire templates available for risk assessments in the AML platform",
        "operationId": "GetAmlRiskAssessmentTemplates",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CodeAndNameDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/aml/clients/{clientId}/contacts": {
      "post": {
        "tags": [
          "AML"
        ],
        "summary": "Add AML Contact",
        "description": "Adds a contact to an existing AML client (account) in the AML platform",
        "operationId": "AddAmlContact",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "clientId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddAmlContactRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AmlContactDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/aml/clients/{clientId}/contacts/{contactId}": {
      "get": {
        "tags": [
          "AML"
        ],
        "summary": "Get AML Contact",
        "description": "Gets a specific contact from an AML client in the AML platform",
        "operationId": "GetAmlContact",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "clientId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "contactId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AmlContactDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "put": {
        "tags": [
          "AML"
        ],
        "summary": "Update AML Contact",
        "description": "Updates a contact in the AML platform",
        "operationId": "UpdateAmlContact",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "clientId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "contactId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateAmlContactRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AmlContactDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/aml/onboarding-levels": {
      "get": {
        "tags": [
          "AML"
        ],
        "summary": "List AML Onboarding Levels",
        "description": "Lists onboarding levels configured in the AML platform",
        "operationId": "GetAmlOnboardingLevels",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AmlOnboardingLevelDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/aml/mail-templates": {
      "get": {
        "tags": [
          "AML"
        ],
        "summary": "List AML Mail Templates",
        "description": "Lists mail templates from the AML platform, filtered by type (ONBOARDING or CLIENT_ONBOARDING)",
        "operationId": "GetAmlMailTemplates",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "type",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 201
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AmlMailTemplateDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/aml/clients/{clientId}/contacts/{contactId}/onboarding-report": {
      "put": {
        "tags": [
          "AML"
        ],
        "summary": "Create Onboarding Report",
        "description": "Creates an onboarding report for a contact in the AML platform",
        "operationId": "CreateOnboardingReport",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "clientId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "contactId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateOnboardingReportRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/aml/clients/{clientId}/contacts/{contactId}/onboarding-url": {
      "get": {
        "tags": [
          "AML"
        ],
        "summary": "Get Onboarding URL",
        "description": "Gets the onboarding URL for a contact. Only available while the onboarding report has status INITIATED.",
        "operationId": "GetAmlOnboardingUrl",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "clientId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "contactId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AmlOnboardingUrlResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/account/keys": {
      "get": {
        "tags": [
          "API Keys"
        ],
        "summary": "List all API keys for the current user",
        "description": "Returns all API keys associated with the currently authenticated user",
        "operationId": "ListApiKeys",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ApiKeyDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "API Keys"
        ],
        "summary": "Create a new API key",
        "description": "Creates a new API key for the currently authenticated user",
        "operationId": "CreateApiKey",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateApiKeyRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/account/keys/{key}": {
      "delete": {
        "tags": [
          "API Keys"
        ],
        "summary": "Delete an API key",
        "description": "Deletes an API key for the currently authenticated user. Use the Key (Guid) as the identifier.",
        "operationId": "DeleteApiKey",
        "parameters": [
          {
            "name": "key",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/agent-authorisations": {
      "get": {
        "tags": [
          "Client - Agent Authorisations"
        ],
        "summary": "List Agent Authorisations",
        "description": "Returns all 11 HMRC 64-8 agent authorisation types for the specified client, each with a user-managed status and a computed IsRequired flag derived from the client's active or proposed services.",
        "operationId": "GetClientAgentAuthorisationStatuses",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ClientAgentAuthorisationDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Client - Agent Authorisations"
        ],
        "summary": "Update Agent Authorisations",
        "description": "Updates the status of one or more HMRC 64-8 agent authorisation types for the specified client. Only the types included in the request are updated; others are left unchanged. Returns the full list of all 11 types.",
        "operationId": "UpdateClientAgentAuthorisationStatuses",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/UpdateClientAgentAuthorisationRequest"
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ClientAgentAuthorisationDto"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/agent-authorisations/hmrc-request": {
      "post": {
        "tags": [
          "Client - Agent Authorisations"
        ],
        "summary": "Send HMRC Authorisation Requests",
        "description": "Creates HMRC agent authorisation requests for the specified types. Digital types (MTD-IT, MTD-VAT) create invitations via the REST API and email the client. Letter-based types (SA, CT, PAYE/CIS) submit via the GovTalk XML API and HMRC posts a code to the client.",
        "operationId": "SendHmrcAuthorisationRequests",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendHmrcAuthorisationRequestDto"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HmrcBatchRequestResult"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/agent-authorisations/hmrc-submit-code": {
      "post": {
        "tags": [
          "Client - Agent Authorisations"
        ],
        "summary": "Submit Letter Auth Code",
        "description": "Submits the authorisation code that HMRC posted to the client (letter-based SA, CT, PAYE/CIS flow). On success the authorisation status is set to Granted.",
        "operationId": "SubmitLetterAuthCode",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubmitLetterAuthCodeRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/agent-authorisations/hmrc-reissue-code/{authorisationType}": {
      "post": {
        "tags": [
          "Client - Agent Authorisations"
        ],
        "summary": "Reissue Letter Auth Code",
        "description": "Requests HMRC to re-issue an authorisation code for a pending letter-based request. HMRC will post a new code to the client.",
        "operationId": "ReissueLetterAuthCode",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "authorisationType",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/AgentAuthorisationType"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/agent-authorisations/hmrc-request/{authorisationType}": {
      "delete": {
        "tags": [
          "Client - Agent Authorisations"
        ],
        "summary": "Cancel HMRC Authorisation Request",
        "description": "Cancels a pending HMRC agent authorisation invitation and resets the record status to Not Requested.",
        "operationId": "CancelHmrcAuthorisationRequest",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "authorisationType",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/AgentAuthorisationType"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/agent-authorisations/hmrc-deauthorise/{authorisationType}": {
      "delete": {
        "tags": [
          "Client - Agent Authorisations"
        ],
        "summary": "Deauthorise HMRC Authorisation",
        "description": "Removes an existing HMRC agent authorisation and resets the record status.",
        "operationId": "DeauthoriseHmrcAuthorisation",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "authorisationType",
            "in": "path",
            "required": true,
            "schema": {
              "$ref": "#/components/schemas/AgentAuthorisationType"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/billinglineitems/clientbillinglineitem": {
      "get": {
        "tags": [
          "Client - Billing - Lines"
        ],
        "summary": "List Billing Line Items for Client",
        "description": "Lists all Billing Line Items for the specified client.",
        "operationId": "ListClientBillingLineItemsForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/ClientBillingLineItemSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter by line item status (Pending, Approved, Invoiced, Cancelled)",
            "schema": {
              "enum": [
                "Pending",
                "Approved",
                "Invoiced",
                "Cancelled"
              ],
              "type": "string",
              "example": "Pending"
            }
          },
          {
            "name": "clientBillableServiceCode",
            "in": "query",
            "description": "Filter by client billable service code",
            "schema": {
              "type": "string",
              "example": "cbs-001"
            }
          },
          {
            "name": "billableServiceCode",
            "in": "query",
            "description": "Filter by billable service code",
            "schema": {
              "type": "string",
              "example": "bs-001"
            }
          },
          {
            "name": "clientCode",
            "in": "query",
            "description": "Filter by client code",
            "schema": {
              "type": "string",
              "example": "ABC123"
            }
          },
          {
            "name": "billingDateFrom",
            "in": "query",
            "description": "Filter to line items with billing date on or after this date (yyyy-MM-dd)",
            "schema": {
              "type": "string",
              "example": "2025-01-01"
            }
          },
          {
            "name": "billingDateTo",
            "in": "query",
            "description": "Filter to line items with billing date on or before this date (yyyy-MM-dd)",
            "schema": {
              "type": "string",
              "example": "2025-12-31"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientBillingLineItemDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Client - Billing - Lines"
        ],
        "summary": "Create Billing Line Item for Client",
        "description": "Creates a new Billing Line Item for the specified client.",
        "operationId": "CreateClientBillingLineItemForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateClientBillingLineItemRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientBillingLineItemDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/billinglineitems/clientbillinglineitem/{code}": {
      "get": {
        "tags": [
          "Client - Billing - Lines"
        ],
        "summary": "Get Billing Line Item for Client",
        "description": "Gets a Billing Line Item for the specified client.",
        "operationId": "GetClientBillingLineItemForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientBillingLineItemDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Client - Billing - Lines"
        ],
        "summary": "Update Billing Line Item for Client",
        "description": "Updates the specified Billing Line Item for the specified client.",
        "operationId": "UpdateClientBillingLineItemForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateClientBillingLineItemRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientBillingLineItemDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Client - Billing - Lines"
        ],
        "summary": "Delete Billing Line Item for Client",
        "description": "Deletes a Billing Line Item for the specified client.",
        "operationId": "DeleteClientBillingLineItemForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/billinglineitems/{code}/status": {
      "patch": {
        "tags": [
          "Client - Billing - Lines"
        ],
        "summary": "Update Billing Line Item Status",
        "description": "Updates the status of a billing line item. Use to approve or cancel a pending line item.",
        "operationId": "UpdateClientBillingLineItemStatus",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateClientBillingLineItemStatusRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/invoicesubmissions/clientinvoicesubmission": {
      "get": {
        "tags": [
          "Client - Billing - Submissions"
        ],
        "summary": "List Invoice Submissions for Client",
        "description": "Lists all Invoice Submissions for the specified client.",
        "operationId": "ListClientInvoiceSubmissionsForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/ClientInvoiceSubmissionSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter by submission status (Pending, Submitted, Failed)",
            "schema": {
              "enum": [
                "Pending",
                "Submitted",
                "Failed",
                "Projected"
              ],
              "type": "string",
              "example": "Failed"
            }
          },
          {
            "name": "clientCode",
            "in": "query",
            "description": "Filter by client code",
            "schema": {
              "type": "string",
              "example": "client-abc"
            }
          },
          {
            "name": "billingDateFrom",
            "in": "query",
            "description": "Filter to submissions with billing date on or after this date (yyyy-MM-dd)",
            "schema": {
              "type": "string",
              "example": "2025-01-01"
            }
          },
          {
            "name": "billingDateTo",
            "in": "query",
            "description": "Filter to submissions with billing date on or before this date (yyyy-MM-dd)",
            "schema": {
              "type": "string",
              "example": "2025-12-31"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientInvoiceSubmissionDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/invoicesubmissions/clientinvoicesubmission/{code}": {
      "get": {
        "tags": [
          "Client - Billing - Submissions"
        ],
        "summary": "Get Invoice Submission for Client",
        "description": "Gets a Invoice Submission for the specified client.",
        "operationId": "GetClientInvoiceSubmissionForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientInvoiceSubmissionDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Client - Billing - Submissions"
        ],
        "summary": "Delete Invoice Submission for Client",
        "description": "Deletes a Invoice Submission for the specified client.",
        "operationId": "DeleteClientInvoiceSubmissionForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/invoicesubmissions/projected": {
      "get": {
        "tags": [
          "Client - Billing - Submissions"
        ],
        "summary": "Get Projected Invoice Submissions",
        "description": "Returns projected invoice submissions that the overnight process would create for this client. Each entry represents a billing date group of approved, unsubmitted line items.",
        "operationId": "GetProjectedInvoiceSubmissionsForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ClientInvoiceSubmissionDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/invoicesubmissions/submit": {
      "post": {
        "tags": [
          "Client - Billing - Submissions"
        ],
        "summary": "Submit Invoice for Client",
        "description": "Creates and pushes a single invoice submission for the specified billing date.",
        "operationId": "SubmitInvoicesForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubmitInvoiceRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceSubmissionResult"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/invoicesubmissions/{code}/retry": {
      "post": {
        "tags": [
          "Client - Billing - Submissions"
        ],
        "summary": "Retry Failed Submission",
        "description": "Retries a failed invoice submission by re-pushing it to the accounting platform.",
        "operationId": "RetryInvoiceSubmission",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceSubmissionResult"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/businessdetails": {
      "get": {
        "tags": [
          "Client - Business Details"
        ],
        "summary": "Get BusinessDetails for a client",
        "operationId": "GetBusinessDetailsForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BusinessDetailsDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Client - Business Details"
        ],
        "summary": "Update BusinessDetails for a client",
        "operationId": "UpdateBusinessDetailsForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BusinessDetailsDto"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BusinessDetailsDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/clientcontact": {
      "get": {
        "tags": [
          "Client - Contacts"
        ],
        "summary": "List Contacts for Client",
        "description": "Lists all Contacts for the specified client.",
        "operationId": "ListClientContactsForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/ClientContactSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "type",
            "in": "query",
            "description": "Filter by contact type",
            "schema": {
              "enum": [
                "Main",
                "Billing",
                "Payroll",
                "Accounts",
                "Director",
                "Psc"
              ],
              "type": "string",
              "example": "Main"
            }
          },
          {
            "name": "role",
            "in": "query",
            "description": "Filter by contact role",
            "schema": {
              "type": "string",
              "example": "Project Manager"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search across contact details: name, email, code (minimum 3 characters)",
            "schema": {
              "type": "string",
              "example": "john"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientContactDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Client - Contacts"
        ],
        "summary": "Create Contact for Client",
        "description": "Creates a client-contact relationship. If Contact.Code is provided and matches an existing contact, that contact will be linked to this client. If Contact.Code is not provided (or empty), a new Contact will be created using the provided contact details (FirstName, LastName, Email, etc.) and then linked to this client.",
        "operationId": "CreateContactForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateClientContactRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientContactDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/clientcontact/{code}": {
      "get": {
        "tags": [
          "Client - Contacts"
        ],
        "summary": "Get Contact for Client",
        "description": "Gets a Contact for the specified client.",
        "operationId": "GetClientContactForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientContactDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Client - Contacts"
        ],
        "summary": "Update Contact for Client",
        "description": "Updates the specified Contact for the specified client.",
        "operationId": "UpdateClientContactForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateClientContactRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientContactDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Client - Contacts"
        ],
        "summary": "Delete Contact for Client",
        "description": "Deletes a Contact for the specified client.",
        "operationId": "DeleteClientContactForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/custom-field-values": {
      "get": {
        "tags": [
          "Client - Custom Fields"
        ],
        "summary": "Get Custom Field Values",
        "description": "Returns field code and value pairs for the specified client. Use the custom field definitions endpoint to retrieve data types, labels, and allowed options.",
        "operationId": "GetClientCustomFieldValues",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CustomFieldValueDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Client - Custom Fields"
        ],
        "summary": "Set Custom Field Values",
        "description": "Sets or updates custom field values for the specified client. Only fields included in the request are updated. Use the custom field definitions endpoint to determine valid field codes and data types.",
        "operationId": "SetClientCustomFieldValues",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/CustomFieldValueDto"
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{code}/dates": {
      "get": {
        "tags": [
          "Client - Dates"
        ],
        "summary": "Get Client Dates",
        "description": "Returns all key dates for the specified client",
        "operationId": "GetClientDates",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ClientDateDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Client - Dates"
        ],
        "summary": "Save Client Dates",
        "description": "Saves or updates key dates for the specified client. Dates with null values will be deleted.",
        "operationId": "SaveClientDates",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/SaveClientDateDto"
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/documentrequest": {
      "get": {
        "tags": [
          "Client - Document Requests"
        ],
        "summary": "List Document Requests for Client",
        "description": "Lists all Document Requests for the specified client.",
        "operationId": "ListDocumentRequestsForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/DocumentRequestSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter by request status (Draft, Open, Submitted, Accepted, Rejected, Cancelled)",
            "schema": {
              "enum": [
                "Draft",
                "Open",
                "Submitted",
                "Accepted",
                "Rejected"
              ],
              "type": "string",
              "example": "Open"
            }
          },
          {
            "name": "clientCode",
            "in": "query",
            "description": "Filter by client code",
            "schema": {
              "type": "string",
              "example": "acme-ltd"
            }
          },
          {
            "name": "managerCode",
            "in": "query",
            "description": "Filter by client manager user code",
            "schema": {
              "type": "string",
              "example": "USR001"
            }
          },
          {
            "name": "partnerCode",
            "in": "query",
            "description": "Filter by client partner user code",
            "schema": {
              "type": "string",
              "example": "USR002"
            }
          },
          {
            "name": "taskCategoryCode",
            "in": "query",
            "description": "Filter by task category code",
            "schema": {
              "type": "string",
              "example": "CAT001"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search across request title and description (minimum 3 characters)",
            "schema": {
              "type": "string",
              "example": "tax returns"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentRequestDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Client - Document Requests"
        ],
        "summary": "Create Document Request",
        "description": "Creates a new document request in Draft status for the specified client.",
        "operationId": "CreateDocumentRequestForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateDocumentRequestRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentRequestDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/documentrequest/{code}": {
      "get": {
        "tags": [
          "Client - Document Requests"
        ],
        "summary": "Get Document Request for Client",
        "description": "Gets a Document Request for the specified client.",
        "operationId": "GetDocumentRequestForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentRequestDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Client - Document Requests"
        ],
        "summary": "Update Document Request for Client",
        "description": "Updates the specified Document Request for the specified client.",
        "operationId": "UpdateDocumentRequestForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateDocumentRequestRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentRequestDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Client - Document Requests"
        ],
        "summary": "Delete Document Request for Client",
        "description": "Deletes a Document Request for the specified client.",
        "operationId": "DeleteDocumentRequestForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/documentrequest/{code}/detail": {
      "get": {
        "tags": [
          "Client - Document Requests"
        ],
        "summary": "Get Document Request Detail",
        "description": "Gets a document request with its associated documents and submission responses.",
        "operationId": "GetDocumentRequestDetailForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentRequestDetailDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/documentrequest/{code}/open": {
      "put": {
        "tags": [
          "Client - Document Requests"
        ],
        "summary": "Open Document Request",
        "description": "Transitions a document request from Draft to Open, making it visible to the client.",
        "operationId": "OpenDocumentRequestForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OpenDocumentRequestRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentRequestDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/documentrequest/{code}/documents": {
      "post": {
        "tags": [
          "Client - Document Requests"
        ],
        "summary": "Upload Document to Request",
        "description": "Uploads a document and attaches it to the specified document request.",
        "operationId": "UploadDocumentToRequestForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "required": [
                  "file"
                ],
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string"
                  },
                  "summary": {
                    "type": "string"
                  },
                  "date": {
                    "type": "string",
                    "format": "date"
                  },
                  "file": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              },
              "encoding": {
                "title": {
                  "style": "form"
                },
                "summary": {
                  "style": "form"
                },
                "date": {
                  "style": "form"
                },
                "file": {
                  "style": "form"
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientDocumentDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/documentrequest/{code}/documents/{documentCode}": {
      "delete": {
        "tags": [
          "Client - Document Requests"
        ],
        "summary": "Remove Document from Request",
        "description": "Removes a document from the specified document request.",
        "operationId": "RemoveDocumentFromRequestForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          },
          {
            "name": "documentCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/documentrequest/{code}/submit": {
      "post": {
        "tags": [
          "Client - Document Requests"
        ],
        "summary": "Submit Document Request",
        "description": "Submits a response to a document request. Comments are required if no documents are attached.",
        "operationId": "SubmitDocumentRequestForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubmitDocumentRequestRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentRequestResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/documentrequest/{code}/responses/{responseCode}/review": {
      "put": {
        "tags": [
          "Client - Document Requests"
        ],
        "summary": "Review Document Request Response",
        "description": "Accepts or rejects a submitted response. On rejection, specify the next action: reopen or reopen and clear documents.",
        "operationId": "ReviewDocumentRequestResponseForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          },
          {
            "name": "responseCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReviewDocumentRequestResponseRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentRequestResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/clientdocument": {
      "get": {
        "tags": [
          "Client - Documents"
        ],
        "summary": "List Documents for Client",
        "description": "Lists all Documents for the specified client.",
        "operationId": "ListClientDocumentsForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/ClientDocumentSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "documentCategoryCode",
            "in": "query",
            "description": "Filter by document category code",
            "schema": {
              "type": "string",
              "example": "engagement-letters"
            }
          },
          {
            "name": "reviewStatus",
            "in": "query",
            "description": "Filter by review status (Approved, PendingReview, Rejected)",
            "schema": {
              "enum": [
                "Approved",
                "PendingReview",
                "Rejected"
              ],
              "type": "string",
              "example": "PendingReview"
            }
          },
          {
            "name": "clientApprovalStatus",
            "in": "query",
            "description": "Filter by client approval status (None, Pending, Approved, Rejected)",
            "schema": {
              "enum": [
                "None",
                "Pending",
                "Approved",
                "Rejected"
              ],
              "type": "string",
              "example": "Pending"
            }
          },
          {
            "name": "clientCode",
            "in": "query",
            "description": "Filter by client code",
            "schema": {
              "type": "string",
              "example": "acme-ltd"
            }
          },
          {
            "name": "managerCode",
            "in": "query",
            "description": "Filter by client manager user code",
            "schema": {
              "type": "string",
              "example": "USR001"
            }
          },
          {
            "name": "partnerCode",
            "in": "query",
            "description": "Filter by client partner user code",
            "schema": {
              "type": "string",
              "example": "USR002"
            }
          },
          {
            "name": "taskCategoryCode",
            "in": "query",
            "description": "Filter by task category code",
            "schema": {
              "type": "string",
              "example": "CAT001"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search across document name and description (minimum 3 characters)",
            "schema": {
              "type": "string",
              "example": "certificate"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientDocumentDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Client - Documents"
        ],
        "summary": "Create Document for Client",
        "description": "Creates a new Document for the specified client.",
        "operationId": "CreateClientDocumentForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          }
        ],
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "required": [
                  "date",
                  "documentCategoryCode",
                  "file",
                  "requestClientApproval",
                  "summary",
                  "title",
                  "visibleInClientPortal"
                ],
                "type": "object",
                "properties": {
                  "documentCategoryCode": {
                    "type": "string"
                  },
                  "title": {
                    "type": "string"
                  },
                  "summary": {
                    "type": "string"
                  },
                  "date": {
                    "type": "string",
                    "format": "date"
                  },
                  "requestClientApproval": {
                    "type": "boolean"
                  },
                  "visibleInClientPortal": {
                    "type": "boolean"
                  },
                  "recipientEmails": {
                    "type": "string"
                  },
                  "folderId": {
                    "type": "string"
                  },
                  "folderPath": {
                    "type": "string"
                  },
                  "portalFolderPath": {
                    "type": "string"
                  },
                  "chaseFrequencyDays": {
                    "type": "integer",
                    "format": "int32"
                  },
                  "file": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              },
              "encoding": {
                "documentCategoryCode": {
                  "style": "form"
                },
                "title": {
                  "style": "form"
                },
                "summary": {
                  "style": "form"
                },
                "date": {
                  "style": "form"
                },
                "requestClientApproval": {
                  "style": "form"
                },
                "visibleInClientPortal": {
                  "style": "form"
                },
                "recipientEmails": {
                  "style": "form"
                },
                "folderId": {
                  "style": "form"
                },
                "folderPath": {
                  "style": "form"
                },
                "portalFolderPath": {
                  "style": "form"
                },
                "chaseFrequencyDays": {
                  "style": "form"
                },
                "file": {
                  "style": "form"
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientDocumentDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/clientdocument/{code}": {
      "get": {
        "tags": [
          "Client - Documents"
        ],
        "summary": "Get Document for Client",
        "description": "Gets a Document for the specified client.",
        "operationId": "GetClientDocumentForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientDocumentDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Client - Documents"
        ],
        "summary": "Update Document for Client",
        "description": "Updates the specified Document for the specified client.",
        "operationId": "UpdateClientDocumentForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateClientDocumentRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientDocumentDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Client - Documents"
        ],
        "summary": "Delete Document for Client",
        "description": "Deletes a Document for the specified client.",
        "operationId": "DeleteClientDocumentForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/external-files": {
      "get": {
        "tags": [
          "Client - Documents"
        ],
        "summary": "List External Files",
        "description": "Lists files from the client's external storage folder, enriched with metadata from the database for files tracked by Sodium. Returns 404 if the tenant has no external storage or the platform doesn't support file listing.",
        "operationId": "ListExternalFilesForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "folderId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExternalDocumentDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/document-folder": {
      "get": {
        "tags": [
          "Client - Documents"
        ],
        "summary": "Get Client Document Folder",
        "description": "Gets the external folder reference for a client's documents. This is only relevant if an external Document Storage provider has been set for the Tenant",
        "operationId": "GetClientDocumentFolder",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExternalFolderReferenceDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Client - Documents"
        ],
        "summary": "Set Client Document Folder",
        "description": "Updates the external folder reference for a client's documents. This is only relevant if an external Document Storage provider has been set for the Tenant",
        "operationId": "UpsertClientDocumentFolder",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpsertBaseFolderRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExternalFolderReferenceDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/clientdocument/{code}/review": {
      "put": {
        "tags": [
          "Client - Documents"
        ],
        "summary": "Review Document",
        "description": "Approve or reject a document uploaded by a client via the portal.",
        "operationId": "ReviewClientDocumentForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReviewClientDocumentRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientDocumentDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/clientdocument/{code}/request-approval": {
      "put": {
        "tags": [
          "Client - Documents"
        ],
        "summary": "Request Client Approval",
        "description": "Request that a client approves a document. The document will appear in the client portal for approval.",
        "operationId": "RequestClientApprovalForDocument",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RequestClientApprovalRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientDocumentDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/clientdocument/{code}/cancel-approval": {
      "put": {
        "tags": [
          "Client - Documents"
        ],
        "summary": "Cancel Client Approval Request",
        "description": "Cancel a pending client approval request, resetting the document to no approval status.",
        "operationId": "CancelClientApprovalForDocument",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientDocumentDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/clientdocument/portal-view": {
      "get": {
        "tags": [
          "Client - Documents"
        ],
        "summary": "Get Portal View",
        "description": "Returns documents and folders as they would appear in the client portal, grouped by PortalFolderPath. Use the portalFolderPath query param to navigate into sub-folders.",
        "operationId": "GetClientDocumentPortalView",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "portalFolderPath",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientDocumentPortalViewResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/clientdocument/from-template": {
      "post": {
        "tags": [
          "Client - Documents"
        ],
        "summary": "Create Document from Template",
        "description": "Generates a PDF from a document template using client data and custom token values, then saves it as a client document.",
        "operationId": "CreateClientDocumentFromTemplateForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateClientDocumentFromTemplateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientDocumentDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/clientdocument/track-external": {
      "post": {
        "tags": [
          "Client - Documents"
        ],
        "summary": "Track External File",
        "description": "Creates a document record for a file that already exists in the external storage provider. No file upload — just associates the external file with Sodium metadata (title, category, visibility, etc.).",
        "operationId": "TrackExternalFileForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TrackExternalFileRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientDocumentDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/clientdocument/{code}/stream": {
      "get": {
        "tags": [
          "Client - Documents"
        ],
        "summary": "Stream Document Content",
        "description": "Streams document content. Requires a valid signed token with tenant and client as query parameters. Use the optional 'disposition' parameter to control the Content-Disposition header: 'attachment' (default) prompts a file download, 'inline' displays the file in the browser for supported types (e.g. PDF, images).",
        "operationId": "StreamClientDocumentForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          },
          {
            "name": "disposition",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "expires",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "x-order": 400
          },
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/external-file/{externalFileId}/stream": {
      "get": {
        "tags": [
          "Client - Documents"
        ],
        "summary": "Stream External File",
        "description": "Proxies and streams file content from an external storage provider. Requires a valid signed token with tenant and client as query parameters.",
        "operationId": "StreamExternalFileForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "disposition",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "expires",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "x-order": 400
          },
          {
            "name": "externalFileId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "fileName",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/clientemailrule": {
      "get": {
        "tags": [
          "Client - Email Rules"
        ],
        "summary": "List Email Rules for Client",
        "description": "Lists all Email Rules for the specified client.",
        "operationId": "ListClientEmailRulesForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/ClientEmailRuleSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search across rule values — email addresses and domains (minimum 3 characters)",
            "schema": {
              "type": "string",
              "example": "acme.com"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientEmailRuleDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Client - Email Rules"
        ],
        "summary": "Create Email Rule for Client",
        "description": "Creates a new Email Rule for the specified client.",
        "operationId": "CreateClientEmailRuleForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateClientEmailRuleRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientEmailRuleDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/clientemailrule/{code}": {
      "get": {
        "tags": [
          "Client - Email Rules"
        ],
        "summary": "Get Email Rule for Client",
        "description": "Gets a Email Rule for the specified client.",
        "operationId": "GetClientEmailRuleForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientEmailRuleDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Client - Email Rules"
        ],
        "summary": "Update Email Rule for Client",
        "description": "Updates the specified Email Rule for the specified client.",
        "operationId": "UpdateClientEmailRuleForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateClientEmailRuleRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientEmailRuleDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Client - Email Rules"
        ],
        "summary": "Delete Email Rule for Client",
        "description": "Deletes a Email Rule for the specified client.",
        "operationId": "DeleteClientEmailRuleForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/emails": {
      "get": {
        "tags": [
          "Client - Emails"
        ],
        "summary": "List Emails for Client",
        "description": "Returns emails associated with this client based on its email rules. Rules containing '@' match that email address, GUIDs pin a specific message, and plain values match all emails from that domain. Searches across mailbox configurations the current user can access (owned or shared). Returns empty results if no rules are configured.",
        "operationId": "GetClientEmails",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 150
          },
          {
            "name": "configCode",
            "in": "query",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "x-order": 400
          },
          {
            "name": "direction",
            "in": "query",
            "description": "Represents the direction of an email in the external mailbox",
            "schema": {
              "$ref": "#/components/schemas/MailboxEmailDirection"
            },
            "x-order": 400
          },
          {
            "name": "folderUniqueId",
            "in": "query",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "format": "uuid"
              }
            },
            "x-order": 400
          },
          {
            "name": "systemFolderType",
            "in": "query",
            "description": "Identifies which provider-system folder a row represents.\nNone (0, the default) means the row is a user-created folder or a Gmail user label.",
            "schema": {
              "$ref": "#/components/schemas/SystemFolderType"
            },
            "x-order": 400
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/MailboxConversationSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MailboxThreadSummaryDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/clientlink": {
      "get": {
        "tags": [
          "Client - Links"
        ],
        "summary": "List Links for Client",
        "description": "Lists all Links for the specified client.",
        "operationId": "ListClientLinksForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/ClientLinkSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientLinkDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Client - Links"
        ],
        "summary": "Create Link for Client",
        "description": "Creates a new Link for the specified client.",
        "operationId": "CreateClientLinkForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateClientLinkRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientLinkDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/clientlink/{code}": {
      "get": {
        "tags": [
          "Client - Links"
        ],
        "summary": "Get Link for Client",
        "description": "Gets a Link for the specified client.",
        "operationId": "GetClientLinkForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientLinkDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Client - Links"
        ],
        "summary": "Update Link for Client",
        "description": "Updates the specified Link for the specified client.",
        "operationId": "UpdateClientLinkForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateClientLinkRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientLinkDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Client - Links"
        ],
        "summary": "Delete Link for Client",
        "description": "Deletes a Link for the specified client.",
        "operationId": "DeleteClientLinkForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/clientnote": {
      "get": {
        "tags": [
          "Client - Notes"
        ],
        "summary": "List Notes for Client",
        "description": "Lists all Notes for the specified client.",
        "operationId": "ListClientNotesForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/ClientNoteSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "authorCode",
            "in": "query",
            "description": "Filter by author (user) code",
            "schema": {
              "type": "string",
              "example": "USR001"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search across note text (minimum 3 characters)",
            "schema": {
              "type": "string",
              "example": "meeting"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NoteDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Client - Notes"
        ],
        "summary": "Create Note for Client",
        "description": "Creates a new note for the specified client. If NoteFromUserCode is not provided, it defaults to the authenticated user.",
        "operationId": "CreateClientNoteForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateClientNoteRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NoteDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/clientnote/{code}": {
      "get": {
        "tags": [
          "Client - Notes"
        ],
        "summary": "Get Note for Client",
        "description": "Gets a Note for the specified client.",
        "operationId": "GetClientNoteForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NoteDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Client - Notes"
        ],
        "summary": "Update Note for Client",
        "description": "Updates the specified Note for the specified client.",
        "operationId": "UpdateClientNoteForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateClientNoteRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NoteDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Client - Notes"
        ],
        "summary": "Delete Note for Client",
        "description": "Deletes a Note for the specified client.",
        "operationId": "DeleteClientNoteForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/clientnote/pinned": {
      "get": {
        "tags": [
          "Client - Notes"
        ],
        "summary": "Get Pinned Notes for Client",
        "description": "Gets all pinned notes for the specified client (PinnedLevel > 0), ordered by PinnedLevel descending.",
        "operationId": "GetPinnedClientNotes",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/NoteDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/pipelines/clientpipeline": {
      "get": {
        "tags": [
          "Client - Pipelines"
        ],
        "summary": "List Client Pipelines for Client",
        "description": "Lists all Client Pipelines for the specified client.",
        "operationId": "ListClientPipelinesForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/ClientPipelineSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientPipelineDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Client - Pipelines"
        ],
        "summary": "Create Client Pipeline for Client",
        "description": "Creates a new Client Pipeline for the specified client.",
        "operationId": "CreateClientPipelineForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateClientPipelineRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientPipelineDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/pipelines/clientpipeline/{code}": {
      "get": {
        "tags": [
          "Client - Pipelines"
        ],
        "summary": "Get Client Pipeline for Client",
        "description": "Gets a Client Pipeline for the specified client.",
        "operationId": "GetClientPipelineForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientPipelineDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Client - Pipelines"
        ],
        "summary": "Update Client Pipeline for Client",
        "description": "Updates the specified Client Pipeline for the specified client.",
        "operationId": "UpdateClientPipelineForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateClientPipelineRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientPipelineDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Client - Pipelines"
        ],
        "summary": "Delete Client Pipeline for Client",
        "description": "Deletes a Client Pipeline for the specified client.",
        "operationId": "DeleteClientPipelineForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/pipelines/{code}/stage": {
      "patch": {
        "tags": [
          "Client - Pipelines"
        ],
        "summary": "Update Client Pipeline Stage",
        "description": "Updates only the stage for a client pipeline card, targeted by the card's own code. Designed for kanban board drag-and-drop — avoids the overhead of a full PUT.",
        "operationId": "UpdateClientPipelineStage",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateClientPipelineStageRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/client-request-settings": {
      "get": {
        "tags": [
          "Client - Request & Chasing"
        ],
        "summary": "Get Client Request Settings",
        "description": "Returns the client request and chasing settings for the specified tenant",
        "operationId": "GetClientRequestSettings",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientRequestSettingsDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "put": {
        "tags": [
          "Client - Request & Chasing"
        ],
        "summary": "Update Client Request Settings",
        "description": "Updates the client request and chasing settings for the specified tenant",
        "operationId": "UpdateClientRequestSettings",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateClientRequestSettingsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientRequestSettingsDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/services/clientbillableservice": {
      "get": {
        "tags": [
          "Client - Services"
        ],
        "summary": "List Client Services for Client",
        "description": "Lists all Client Services for the specified client.",
        "operationId": "ListClientBillableServicesForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/ClientBillableServiceSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientBillableServiceDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Client - Services"
        ],
        "summary": "Create Client Service for Client",
        "description": "Creates a new Client Service for the specified client.",
        "operationId": "CreateClientBillableServiceForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateClientBillableServiceRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientBillableServiceDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/services/clientbillableservice/{code}": {
      "get": {
        "tags": [
          "Client - Services"
        ],
        "summary": "Get Client Service for Client",
        "description": "Gets a Client Service for the specified client.",
        "operationId": "GetClientBillableServiceForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientBillableServiceDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Client - Services"
        ],
        "summary": "Update Client Service for Client",
        "description": "Updates the specified Client Service for the specified client.",
        "operationId": "UpdateClientBillableServiceForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateClientBillableServiceRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientBillableServiceDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Client - Services"
        ],
        "summary": "Delete Client Service for Client",
        "description": "Deletes a Client Service for the specified client.",
        "operationId": "DeleteClientBillableServiceForClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/services/required-fields": {
      "get": {
        "tags": [
          "Client - Services"
        ],
        "summary": "Get Required Client Fields",
        "description": "Returns client fields that are required by recurring tasks linked to the client's active services.",
        "operationId": "GetRequiredClientFields",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ClientCsvTargetField"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/services/{code}/stage": {
      "patch": {
        "tags": [
          "Client - Services"
        ],
        "summary": "Update Client Service Stage",
        "description": "Updates only the stage for a client billable service, targeted by the assignment's own code (a client can hold multiple instances of the same service). Designed for kanban board drag-and-drop — avoids the overhead of a full PUT.",
        "operationId": "UpdateClientBillableServiceStage",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateClientBillableServiceStageRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/services/{code}/stage-history": {
      "get": {
        "tags": [
          "Client - Services"
        ],
        "summary": "Get Client Service Stage History",
        "description": "Returns the stage-change history for a client billable service, newest first — the audit trail behind time-in-stage reporting.",
        "operationId": "GetClientBillableServiceStageHistory",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ClientBillableServiceStageHistoryDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/client-settings": {
      "get": {
        "tags": [
          "Client - Settings"
        ],
        "summary": "Get client settings",
        "description": "Returns the client settings for the specified tenant",
        "operationId": "GetClientSettings",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientSettingsDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "put": {
        "tags": [
          "Client - Settings"
        ],
        "summary": "Update client settings",
        "description": "Updates the client settings for the specified tenant",
        "operationId": "UpdateClientSettings",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateClientSettingsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientSettingsDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clientbillableservices": {
      "get": {
        "tags": [
          "Client Billable Services"
        ],
        "summary": "List Client Service Summaries",
        "description": "Returns a paged list of client billable service summaries across all clients. Returns a lightweight projection (not the full DTO) designed for kanban board display. Filter by serviceCode and stageCode to load a single kanban column.",
        "operationId": "ListClientBillableServiceSummaries",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "includeTasks",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "x-order": 400
          },
          {
            "name": "verbose",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "x-order": 400
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/ClientBillableServiceSummarySortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "serviceCode",
            "in": "query",
            "description": "Filter by billable service code",
            "schema": {
              "type": "string",
              "example": "bookkeeping"
            }
          },
          {
            "name": "stageCode",
            "in": "query",
            "description": "Filter by stage code",
            "schema": {
              "type": "string",
              "example": "in-progress"
            }
          },
          {
            "name": "taskCategoryCode",
            "in": "query",
            "description": "Filter tasks on kanban cards by task category code",
            "schema": {
              "type": "string",
              "example": "vat"
            }
          },
          {
            "name": "clientManagerCode",
            "in": "query",
            "description": "Filter by client manager user code",
            "schema": {
              "type": "string",
              "example": "john-smith"
            }
          },
          {
            "name": "partnerCode",
            "in": "query",
            "description": "Filter by partner user code",
            "schema": {
              "type": "string",
              "example": "jane-doe"
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter by service assignment status",
            "schema": {
              "type": "string",
              "example": "Active"
            }
          },
          {
            "name": "managedByUserCode",
            "in": "query",
            "description": "Filter by managed-by user code",
            "schema": {
              "type": "string",
              "example": "john-smith"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search across client name and code (minimum 3 characters)",
            "schema": {
              "type": "string",
              "example": "acme"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientBillableServiceSummaryDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/clientbillableservices/stage-counts": {
      "get": {
        "tags": [
          "Client Billable Services"
        ],
        "summary": "Get Client Service Stage Counts",
        "description": "Returns per-stage card counts for a service's kanban board, including each stage's display settings (icon, colour, sort order). One row per stage, including empty stages, in board display order. Designed for dashboard widgets — a single lightweight query instead of loading board columns.",
        "operationId": "GetClientBillableServiceStageCounts",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "serviceCode",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/KanbanStageCountDto"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/billinglineitems": {
      "get": {
        "tags": [
          "Client Billing - Line Items"
        ],
        "summary": "List Billing Line Items",
        "description": "Returns a paged list of billing line items across all clients for the tenant. Supports filtering by status, client, and billing date range.",
        "operationId": "ListBillingLineItems",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/ClientBillingLineItemSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter by line item status (Pending, Approved, Invoiced, Cancelled)",
            "schema": {
              "enum": [
                "Pending",
                "Approved",
                "Invoiced",
                "Cancelled"
              ],
              "type": "string",
              "example": "Pending"
            }
          },
          {
            "name": "clientBillableServiceCode",
            "in": "query",
            "description": "Filter by client billable service code",
            "schema": {
              "type": "string",
              "example": "cbs-001"
            }
          },
          {
            "name": "billableServiceCode",
            "in": "query",
            "description": "Filter by billable service code",
            "schema": {
              "type": "string",
              "example": "bs-001"
            }
          },
          {
            "name": "clientCode",
            "in": "query",
            "description": "Filter by client code",
            "schema": {
              "type": "string",
              "example": "ABC123"
            }
          },
          {
            "name": "billingDateFrom",
            "in": "query",
            "description": "Filter to line items with billing date on or after this date (yyyy-MM-dd)",
            "schema": {
              "type": "string",
              "example": "2025-01-01"
            }
          },
          {
            "name": "billingDateTo",
            "in": "query",
            "description": "Filter to line items with billing date on or before this date (yyyy-MM-dd)",
            "schema": {
              "type": "string",
              "example": "2025-12-31"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientBillingLineItemDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/client-billing-settings": {
      "get": {
        "tags": [
          "Client Billing - Settings"
        ],
        "summary": "Get client billing settings",
        "description": "Returns the client billing settings for the specified tenant",
        "operationId": "GetClientBilling-Settings",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientBillingSettingsDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "put": {
        "tags": [
          "Client Billing - Settings"
        ],
        "summary": "Update client billing settings",
        "description": "Updates the client billing settings for the specified tenant",
        "operationId": "UpdateClientBilling-Settings",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateClientBillingSettingsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientBillingSettingsDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/invoicesubmissions": {
      "get": {
        "tags": [
          "Client Billing - Submissions"
        ],
        "summary": "List Invoice Submissions",
        "description": "Returns a paged list of invoice submissions across all clients for the tenant. Supports filtering by status, client, and billing date range.",
        "operationId": "ListInvoiceSubmissions",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/ClientInvoiceSubmissionSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter by submission status (Pending, Submitted, Failed)",
            "schema": {
              "enum": [
                "Pending",
                "Submitted",
                "Failed",
                "Projected"
              ],
              "type": "string",
              "example": "Failed"
            }
          },
          {
            "name": "clientCode",
            "in": "query",
            "description": "Filter by client code",
            "schema": {
              "type": "string",
              "example": "client-abc"
            }
          },
          {
            "name": "billingDateFrom",
            "in": "query",
            "description": "Filter to submissions with billing date on or after this date (yyyy-MM-dd)",
            "schema": {
              "type": "string",
              "example": "2025-01-01"
            }
          },
          {
            "name": "billingDateTo",
            "in": "query",
            "description": "Filter to submissions with billing date on or before this date (yyyy-MM-dd)",
            "schema": {
              "type": "string",
              "example": "2025-12-31"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientInvoiceSubmissionDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/client-confirmations": {
      "get": {
        "tags": [
          "Client Confirmations"
        ],
        "summary": "List Client Confirmations",
        "description": "Returns a paged list of client confirmation workflow steps across all clients. Filter by status and client code.",
        "operationId": "ListClientConfirmations",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/ClientConfirmationSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "clientCode",
            "in": "query",
            "description": "Filter by client code",
            "schema": {
              "type": "string",
              "example": "acme-ltd"
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter by status (NotStarted, InProgress, Blocked, Completed, Skipped)",
            "schema": {
              "enum": [
                "NotStarted",
                "InProgress",
                "Blocked",
                "Completed",
                "Skipped"
              ],
              "type": "string",
              "example": "InProgress"
            }
          },
          {
            "name": "managerCode",
            "in": "query",
            "description": "Filter by client manager user code",
            "schema": {
              "type": "string",
              "example": "USR001"
            }
          },
          {
            "name": "partnerCode",
            "in": "query",
            "description": "Filter by client partner user code",
            "schema": {
              "type": "string",
              "example": "USR002"
            }
          },
          {
            "name": "taskCategoryCode",
            "in": "query",
            "description": "Filter by task category code",
            "schema": {
              "type": "string",
              "example": "CAT001"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search across step name, task title, and client name (minimum 3 characters)",
            "schema": {
              "type": "string",
              "example": "tax return"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientConfirmationDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/clientdocuments": {
      "get": {
        "tags": [
          "Client Documents"
        ],
        "summary": "List Client Documents",
        "description": "Returns a paged list of client documents across all clients. Defaults to only showing documents sent for client approval (ClientApprovalStatus != None).",
        "operationId": "ListAllClientDocuments",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/ClientDocumentSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "documentCategoryCode",
            "in": "query",
            "description": "Filter by document category code",
            "schema": {
              "type": "string",
              "example": "engagement-letters"
            }
          },
          {
            "name": "reviewStatus",
            "in": "query",
            "description": "Filter by review status (Approved, PendingReview, Rejected)",
            "schema": {
              "enum": [
                "Approved",
                "PendingReview",
                "Rejected"
              ],
              "type": "string",
              "example": "PendingReview"
            }
          },
          {
            "name": "clientApprovalStatus",
            "in": "query",
            "description": "Filter by client approval status (None, Pending, Approved, Rejected)",
            "schema": {
              "enum": [
                "None",
                "Pending",
                "Approved",
                "Rejected"
              ],
              "type": "string",
              "example": "Pending"
            }
          },
          {
            "name": "clientCode",
            "in": "query",
            "description": "Filter by client code",
            "schema": {
              "type": "string",
              "example": "acme-ltd"
            }
          },
          {
            "name": "managerCode",
            "in": "query",
            "description": "Filter by client manager user code",
            "schema": {
              "type": "string",
              "example": "USR001"
            }
          },
          {
            "name": "partnerCode",
            "in": "query",
            "description": "Filter by client partner user code",
            "schema": {
              "type": "string",
              "example": "USR002"
            }
          },
          {
            "name": "taskCategoryCode",
            "in": "query",
            "description": "Filter by task category code",
            "schema": {
              "type": "string",
              "example": "CAT001"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search across document name and description (minimum 3 characters)",
            "schema": {
              "type": "string",
              "example": "certificate"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientDocumentDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/clientpipelines": {
      "get": {
        "tags": [
          "Client Pipelines"
        ],
        "summary": "List Client Pipeline Summaries",
        "description": "Returns a paged list of client pipeline card summaries across all clients. Returns a lightweight projection designed for kanban board display. Filter by pipelineCode and stageCode to load a single kanban column.",
        "operationId": "ListClientPipelineSummaries",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "includeTasks",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "x-order": 400
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/ClientPipelineSummarySortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "pipelineCode",
            "in": "query",
            "description": "Filter by pipeline code",
            "schema": {
              "type": "string",
              "example": "sales-pipeline"
            }
          },
          {
            "name": "stageCode",
            "in": "query",
            "description": "Filter by stage code",
            "schema": {
              "type": "string",
              "example": "new-lead"
            }
          },
          {
            "name": "taskCategoryCode",
            "in": "query",
            "description": "Filter tasks on kanban cards by task category code",
            "schema": {
              "type": "string",
              "example": "follow-up"
            }
          },
          {
            "name": "clientManagerCode",
            "in": "query",
            "description": "Filter by client manager user code",
            "schema": {
              "type": "string",
              "example": "john-smith"
            }
          },
          {
            "name": "partnerCode",
            "in": "query",
            "description": "Filter by partner user code",
            "schema": {
              "type": "string",
              "example": "jane-doe"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search across client name and code (minimum 3 characters)",
            "schema": {
              "type": "string",
              "example": "acme"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientPipelineSummaryDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/clientpipelines/stage-counts": {
      "get": {
        "tags": [
          "Client Pipelines"
        ],
        "summary": "Get Client Pipeline Stage Counts",
        "description": "Returns per-stage card counts for a pipeline's kanban board, including each stage's display settings (icon, colour, sort order). One row per stage, including empty stages, in board display order. Designed for dashboard widgets — a single lightweight query instead of loading board columns.",
        "operationId": "GetClientPipelineStageCounts",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "pipelineCode",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/KanbanStageCountDto"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/contacts/{code}/portal-access": {
      "put": {
        "tags": [
          "Client Portal - Access"
        ],
        "summary": "Set Portal Access",
        "description": "Grant or revoke portal access for a contact on a client. When granting access, a PortalUser record is automatically created if one doesn't exist for the contact.",
        "operationId": "SetPortalAccess",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetPortalAccessRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientContactDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{client}/contacts/{code}/portal-access/send-invitation": {
      "post": {
        "tags": [
          "Client Portal - Access"
        ],
        "summary": "Send Portal Invitation",
        "description": "Sends or re-sends the portal invitation email. The contact must already have portal access granted.",
        "operationId": "SendPortalInvitation",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "client",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 1
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortalUserDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/client-portal-settings": {
      "get": {
        "tags": [
          "Client Portal - Settings"
        ],
        "summary": "Get client portal settings",
        "description": "Returns the client portal settings for the specified tenant",
        "operationId": "GetClientPortalSettings",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientPortalSettingsDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "put": {
        "tags": [
          "Client Portal - Settings"
        ],
        "summary": "Update client portal settings",
        "description": "Updates the client portal settings for the specified tenant",
        "operationId": "UpdateClientPortalSettings",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateClientPortalSettingsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientPortalSettingsDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/portal-users": {
      "get": {
        "tags": [
          "Client Portal - Users"
        ],
        "summary": "List Portal Users",
        "description": "Returns all portal users for this tenant.",
        "operationId": "ListPortalUsers",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PortalUserDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/portal-users/{code}/status": {
      "put": {
        "tags": [
          "Client Portal - Users"
        ],
        "summary": "Update Portal User Status",
        "description": "Enable or disable a portal user account. Disabling prevents login without revoking per-client access grants.",
        "operationId": "UpdatePortalUserStatus",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdatePortalUserStatusRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortalUserDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients": {
      "post": {
        "tags": [
          "Clients"
        ],
        "summary": "Create Client",
        "description": "Creates a new Client for the specified tenant.",
        "operationId": "CreateClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateClientRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "get": {
        "tags": [
          "Clients"
        ],
        "summary": "List Clients",
        "description": "Lists Clients for the given tenant.\n\nSupports filtering by manager, partner, associate, status, type, service, and search term.\nOptionally apply a saved filter by code — saved filter values are used unless explicitly overridden by query parameters.",
        "operationId": "ListClients",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "savedFilter",
            "in": "query",
            "description": "Code of a saved filter to apply. When provided, all filter parameters from the saved filter are used unless explicitly overridden by query parameters.",
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/ClientSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "managerCode",
            "in": "query",
            "description": "Filter clients by their assigned manager's code (repeat parameter for multiple values)",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "MGR001"
            }
          },
          {
            "name": "partnerCode",
            "in": "query",
            "description": "Filter clients by their assigned partner's code (repeat parameter for multiple values)",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "PTR001"
            }
          },
          {
            "name": "associateCode",
            "in": "query",
            "description": "Filter clients by their assigned associate's code (repeat parameter for multiple values)",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "ASC001"
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter clients by status (repeat parameter for multiple values)",
            "schema": {
              "type": "array",
              "items": {
                "enum": [
                  "Active",
                  "Inactive",
                  "Prospect",
                  "LostProspect"
                ],
                "type": "string"
              },
              "example": "Active"
            }
          },
          {
            "name": "type",
            "in": "query",
            "description": "Filter clients by their organization type (repeat parameter for multiple values)",
            "schema": {
              "type": "array",
              "items": {
                "enum": [
                  "PrivateLimitedCompany",
                  "PublicLimitedCompany",
                  "LimitedLiabilityPartnership",
                  "Partnership",
                  "Individual",
                  "Trust",
                  "Charity",
                  "SoleTrader"
                ],
                "type": "string"
              },
              "example": "PrivateLimitedCompany"
            }
          },
          {
            "name": "serviceCode",
            "in": "query",
            "description": "Filter clients by billable service codes they have assigned (repeat parameter for multiple values)",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "SVC001"
            }
          },
          {
            "name": "packageCode",
            "in": "query",
            "description": "Filter clients by service package codes they have assigned (repeat parameter for multiple values)",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "PKG001"
            }
          },
          {
            "name": "teamCode",
            "in": "query",
            "description": "Filter clients by their assigned team's code (repeat parameter for multiple values)",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "TEAM001"
            }
          },
          {
            "name": "serviceStageCode",
            "in": "query",
            "description": "Filter clients by service stage using composite codes in the format serviceCode:stageCode (repeat parameter for multiple values)",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "SVC001:in-progress"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search across client code, name and internal reference (minimum 3 characters)",
            "schema": {
              "type": "string",
              "example": "acme"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientDtoPagedResult"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "patch": {
        "tags": [
          "Clients"
        ],
        "summary": "Bulk Update Clients",
        "description": "Updates multiple clients at once. Supports updating partner, manager, associate, PCL sent status, client status, and contact preferences (post, telephone, email, SMS). At least one update field must be provided. For role fields (PartnerCode, ManagerCode, AssociateCode): omit or null to leave unchanged, pass a user code to assign, or pass an empty string to unassign.",
        "operationId": "BulkUpdateClients",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkUpdateClientsRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkUpdateResult"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{code}": {
      "get": {
        "tags": [
          "Clients"
        ],
        "summary": "Get Client",
        "description": "Gets a Client for the specified tenant.",
        "operationId": "GetClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Clients"
        ],
        "summary": "Update Client",
        "description": "Updates a Client for the specified tenant.",
        "operationId": "UpdateClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateClientRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Clients"
        ],
        "summary": "Delete Client",
        "description": "Deletes a Client for the specified tenant.",
        "operationId": "DeleteClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{code}/resolve-recipients": {
      "post": {
        "tags": [
          "Clients"
        ],
        "summary": "Resolve Email Recipients",
        "description": "Resolves email recipient configuration (contact types, user roles, static emails) to actual email addresses for the specified client. Returns deduplicated list of recipients with names and email addresses.",
        "operationId": "ResolveClientEmailRecipients",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmailRecipientConfig"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EmailRecipient"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{code}/tasks/summary": {
      "get": {
        "tags": [
          "Clients"
        ],
        "summary": "Task Summary",
        "description": "Returns a count of top-level tasks grouped by status for the specified client (excludes child tasks)",
        "operationId": "GetClientTaskSummary",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskSummaryDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/third-party-mappings": {
      "get": {
        "tags": [
          "Clients"
        ],
        "summary": "List Third-Party Mappings",
        "description": "Returns a paged list of clients with their accounting, direct debit and AML mapping identifiers. Use the 'unmapped' query parameter to filter to clients missing a specific mapping (values: accounting, directdebit, aml).",
        "operationId": "ListClientThirdPartyMappings",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "unmapped",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/ClientThirdPartyMappingSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientThirdPartyMappingDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{code}/third-party-mappings": {
      "patch": {
        "tags": [
          "Clients"
        ],
        "summary": "Update Third-Party Mapping",
        "description": "Updates the accounting, direct debit and/or AML mapping identifiers for a single client.",
        "operationId": "UpdateClientThirdPartyMapping",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateClientThirdPartyMappingRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientThirdPartyMappingDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/export/csv": {
      "post": {
        "tags": [
          "Clients - CSV Export"
        ],
        "summary": "Start CSV Export",
        "description": "Starts an async export of clients to CSV format. Optionally specify a saved mapping or inline column mappings to control the output format. If no mapping is provided, all fields are exported with enum names as headers. Use the filter options to select which clients to include. Returns 201 Created with downloadUrl if the export completes within 10 seconds, or 202 Accepted with a Location header to poll for completion.",
        "operationId": "StartClientCsvExport",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CsvExportRequestDto"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CsvExportJobDto"
                }
              }
            }
          },
          "202": {
            "description": "Accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CsvExportJobDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/export/csv/{code}": {
      "get": {
        "tags": [
          "Clients - CSV Export"
        ],
        "summary": "Get Export Status",
        "description": "Returns the current status and progress of a CSV export job. Poll this endpoint after receiving a 202 Accepted response. When status is 'Completed', the downloadUrl field contains a time-limited link to download the CSV file.",
        "operationId": "GetClientCsvExportStatus",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CsvExportJobDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/import/csv": {
      "post": {
        "tags": [
          "Clients - CSV Import"
        ],
        "summary": "Upload Client CSV",
        "description": "Uploads a CSV file for importing clients. With showPreview=true (default), returns 201 with preview data. With showPreview=false and a mapping provided, returns 202 and starts import.\n\n**Header Detection:**\n- If `hasHeaderRow` is provided, that value is used\n- If `hasHeaderRow` is omitted, the system auto-detects by analyzing the first row for known header patterns (e.g., \"Company Name\", \"Email\") and data patterns (e.g., email addresses, phone numbers)\n- The response includes the actual `hasHeaderRow` value used (whether explicit or auto-detected)\n\n**Synthetic Headers:**\nWhen `hasHeaderRow` is false (explicitly or detected), the system generates synthetic column headers: Column1, Column2, Column3, etc. Use these synthetic names when creating column mappings for headerless CSV files.",
        "operationId": "UploadCsvForImport",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "required": [
                  "file"
                ],
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "description": "The CSV file to upload. Must be a valid CSV file with UTF-8 encoding.",
                    "format": "binary"
                  },
                  "hasHeaderRow": {
                    "type": "boolean",
                    "description": "Whether the CSV file has a header row. When true, the first row is treated as column headers. When false, synthetic column headers are generated (Column1, Column2, etc.) which can be used in column mappings. If not provided, the system will auto-detect based on the first row content."
                  },
                  "showPreview": {
                    "type": "boolean",
                    "description": "When true (default), returns a preview of the CSV data with auto-suggested mappings without starting the import. Set to false to start the import immediately (requires mapping to be provided)."
                  },
                  "mappingCode": {
                    "type": "string",
                    "description": "Code of a saved mapping to use. Either mappingCode or columnMappingsJson must be provided when showPreview=false."
                  },
                  "columnMappingsJson": {
                    "type": "string",
                    "description": "JSON array of column mappings for inline/ad-hoc mapping. Format: [{\"csvHeader\":\"Company Name\",\"targetField\":\"Name\"}]. Either mappingCode or columnMappingsJson must be provided when showPreview=false."
                  },
                  "matchField": {
                    "$ref": "#/components/schemas/CsvImportMatchField"
                  },
                  "importMode": {
                    "$ref": "#/components/schemas/CsvImportMode"
                  },
                  "enrichFromCompaniesHouse": {
                    "type": "boolean",
                    "description": "Whether to enrich newly created clients with Companies House data. Only applies to eligible company types (excludes Individual, SoleTrader, Trust). Default: false."
                  }
                }
              },
              "encoding": {
                "file": {
                  "style": "form"
                },
                "hasHeaderRow": {
                  "style": "form"
                },
                "showPreview": {
                  "style": "form"
                },
                "mappingCode": {
                  "style": "form"
                },
                "columnMappingsJson": {
                  "style": "form"
                },
                "matchField": {
                  "style": "form"
                },
                "importMode": {
                  "style": "form"
                },
                "enrichFromCompaniesHouse": {
                  "style": "form"
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CsvUploadResponseDto"
                }
              }
            }
          },
          "202": {
            "description": "Accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CsvImportJobDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/import/csv/{code}": {
      "get": {
        "tags": [
          "Clients - CSV Import"
        ],
        "summary": "Get Import Status",
        "description": "Returns the current status and progress of a CSV import job. Poll this endpoint after receiving a 202 Accepted response.",
        "operationId": "GetCsvImportStatus",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CsvImportJobDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Clients - CSV Import"
        ],
        "summary": "Start CSV Import",
        "description": "Confirms the column mapping and starts the CSV import. Call after uploading with showPreview=true.",
        "operationId": "ConfirmCsvImport",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConfirmCsvImportRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CsvImportJobDto"
                }
              }
            }
          },
          "202": {
            "description": "Accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CsvImportJobDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/import/available": {
      "get": {
        "tags": [
          "Clients - Platform Import"
        ],
        "summary": "List Available Clients",
        "description": "Returns a paginated list of clients available for import from the specified third-party connection. This endpoint does not import any data - it only lists what is available. Shows which clients have already been imported via the ImportedAs field.",
        "operationId": "GetAvailableClientsForImport",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "connectionCode",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AvailableClientDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "502": {
            "description": "Bad Gateway",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        }
      }
    },
    "/tenants/{tenant}/clients/import/from-connection": {
      "post": {
        "tags": [
          "Clients - Platform Import"
        ],
        "summary": "Import clients from a third-party connection",
        "description": "Imports clients from the third-party platform. This endpoint uses a hybrid approach: it queues the import job and waits up to 10 seconds for completion. For small imports (5-20 clients), the job typically completes within this window and returns 201 Created with the final result. For larger imports that take longer, it returns 202 Accepted with a Location header pointing to the import job status endpoint. If importAll query parameter is true, imports all available clients and ignores the request body. Otherwise, imports only the clients specified by external IDs in the request body. If enrichFromCompaniesHouse is true, enriches eligible companies with Companies House data (excludes Individual, SoleTrader, Trust).",
        "operationId": "ImportClientsFromConnection",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "connectionCode",
            "in": "query",
            "description": "The code of the third-party connection to import from (e.g., 'xero-abc123')",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "enrichFromCompaniesHouse",
            "in": "query",
            "description": "When true, enriches newly imported companies with Companies House data (business details, key dates, officer contacts). Only applies to eligible company types (excludes Individual, SoleTrader, Trust). Default: false.",
            "schema": {
              "type": "boolean"
            },
            "x-order": 400
          },
          {
            "name": "importAll",
            "in": "query",
            "description": "When true, imports all available clients from the platform and ignores the request body. When false (default), only imports clients specified by ExternalIds in the request body.",
            "schema": {
              "type": "boolean"
            },
            "x-order": 400
          }
        ],
        "requestBody": {
          "description": "Request body containing external IDs to import",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClientImportRequestDto"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImportJobDto"
                }
              }
            }
          },
          "202": {
            "description": "Accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImportJobDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImportJobDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/import/map-client": {
      "post": {
        "tags": [
          "Clients - Platform Import"
        ],
        "summary": "Map External Client",
        "description": "Manually maps an external platform client to an existing Sodium client. Creates an ImportedClients record with IsManuallyMapped = true, allowing the external client to be linked without importing a new record.",
        "operationId": "MapExternalClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "connectionCode",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MapExternalClientRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          }
        }
      }
    },
    "/tenants/{tenant}/saved-client-filters": {
      "get": {
        "tags": [
          "Clients - Saved Filters"
        ],
        "summary": "List SavedClientFilters",
        "description": "Lists the saved client filters visible to the current user within the tenant: their own filters plus any shared with the practice.",
        "operationId": "ListSavedClientFilters",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/SavedClientFilterSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "menuOnly",
            "in": "query",
            "description": "Filter to only show filters marked for menu display",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search across saved view name and description",
            "schema": {
              "type": "string",
              "example": "vat"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SavedClientFilterDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "post": {
        "tags": [
          "Clients - Saved Filters"
        ],
        "summary": "Create SavedClientFilter",
        "description": "Creates a new saved client filter owned by the current user.",
        "operationId": "CreateSavedClientFilter",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateSavedClientFilterRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SavedClientFilterDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/saved-client-filters/{code}": {
      "get": {
        "tags": [
          "Clients - Saved Filters"
        ],
        "summary": "Get SavedClientFilter",
        "description": "Gets a specific saved client filter by code. Only filters owned by or shared with the current user are accessible.",
        "operationId": "GetSavedClientFilter",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SavedClientFilterDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Clients - Saved Filters"
        ],
        "summary": "Update SavedClientFilter",
        "description": "Updates an existing saved client filter. Only the owner can update a filter.",
        "operationId": "UpdateSavedClientFilter",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateSavedClientFilterRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SavedClientFilterDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Clients - Saved Filters"
        ],
        "summary": "Delete SavedClientFilter",
        "description": "Deletes a saved client filter. Only the owner can delete a filter.",
        "operationId": "DeleteSavedClientFilter",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/saved-client-filters/{code}/menu": {
      "put": {
        "tags": [
          "Clients - Saved Filters"
        ],
        "summary": "Set Menu Preference",
        "description": "Sets whether this saved client filter appears in the current user's menu. This is a per-user preference and does not affect other users.",
        "operationId": "SetSavedClientFilterMenuPreference",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetSavedFilterMenuRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/client-services/import/csv/preview": {
      "post": {
        "tags": [
          "Clients - Services - Import"
        ],
        "summary": "Preview Service CSV Import",
        "description": "Uploads a native-format CSV and returns a preview of what the import will do: new assignments, updates to existing assignments, and unchanged assignments. The file is stored for the confirm step.",
        "operationId": "PreviewServiceCsvImport",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "required": [
                  "file",
                  "matchField"
                ],
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  },
                  "matchField": {
                    "$ref": "#/components/schemas/CsvImportMatchField"
                  },
                  "createOnboardingTasks": {
                    "type": "boolean"
                  }
                }
              },
              "encoding": {
                "file": {
                  "style": "form"
                },
                "matchField": {
                  "style": "form"
                },
                "createOnboardingTasks": {
                  "style": "form"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceImportPreviewDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          }
        }
      }
    },
    "/tenants/{tenant}/client-services/import/csv/{code}/confirm": {
      "put": {
        "tags": [
          "Clients - Services - Import"
        ],
        "summary": "Confirm Service CSV Import",
        "description": "Confirms a previously previewed import and queues it for background processing. Returns 201 if completed within 10 seconds, 202 if still processing.",
        "operationId": "ConfirmServiceCsvImport",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceImportJobDto"
                }
              }
            }
          },
          "202": {
            "description": "Accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceImportJobDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/client-services/import/csv/export": {
      "get": {
        "tags": [
          "Clients - Services - Import"
        ],
        "summary": "Export Client Services CSV",
        "description": "Downloads all client service assignments as a CSV file. Use this as a template for the native import format.",
        "operationId": "ExportServicesCsv",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "serviceCode",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          }
        }
      }
    },
    "/tenants/{tenant}/client-services/import/csv/{code}": {
      "get": {
        "tags": [
          "Clients - Services - Import"
        ],
        "summary": "Get Service Import Status",
        "description": "Returns the current status and progress of a service import job. Poll this endpoint after starting the import.",
        "operationId": "GetServiceImportStatus",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceImportJobDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/client-services/import/csv/analyze": {
      "post": {
        "tags": [
          "Clients - Services - Import"
        ],
        "summary": "Analyze Service CSV",
        "description": "Auto-detects the source format (Engager or Bright AM) and returns its detected services with client counts. Stateless: no data is persisted.",
        "operationId": "AnalyzeServiceCsv",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "required": [
                  "file"
                ],
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              },
              "encoding": {
                "file": {
                  "style": "form"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/DetectedServiceDto"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          }
        }
      }
    },
    "/tenants/{tenant}/client-services/import/csv/convert": {
      "post": {
        "tags": [
          "Clients - Services - Import"
        ],
        "summary": "Convert Service CSV to Native Format",
        "description": "Auto-detects the source format and converts the file plus service mappings into a native-format CSV for download. Stateless: no data is persisted.",
        "operationId": "ConvertServiceCsv",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "required": [
                  "file",
                  "mappings"
                ],
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  },
                  "mappings": {
                    "type": "string"
                  }
                }
              },
              "encoding": {
                "file": {
                  "style": "form"
                },
                "mappings": {
                  "style": "form"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          }
        }
      }
    },
    "/tenants/{tenant}/companies-house/search": {
      "get": {
        "tags": [
          "Companies House"
        ],
        "summary": "Search",
        "description": "Search the Companies House register for companies matching the query - either name or number",
        "operationId": "SearchCompanies",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "itemsPerPage",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 20
            },
            "x-order": 400
          },
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "startIndex",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 0
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompanySearchResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/companies-house/{companyNumber}": {
      "get": {
        "tags": [
          "Companies House"
        ],
        "summary": "Get Company Details",
        "description": "Retrieve detailed information about a specific company",
        "operationId": "GetCompanyDetails",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "companyNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Company"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/companies-house/{companyNumber}/officers": {
      "get": {
        "tags": [
          "Companies House"
        ],
        "summary": "Get Company Officers",
        "description": "Retrieve the list of current and former officers for a company",
        "operationId": "GetCompanyOfficers",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "companyNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Officer"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/companies-house/{companyNumber}/key-dates": {
      "get": {
        "tags": [
          "Companies House"
        ],
        "summary": "Get Key Dates",
        "description": "Retrieve important upcoming dates for a company",
        "operationId": "GetCompanyKeyDates",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "companyNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ClientDateDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/companies-house/{companyNumber}/filing-history": {
      "get": {
        "tags": [
          "Companies House"
        ],
        "summary": "Get Filing History",
        "description": "Retrieve the filing history for a company",
        "operationId": "GetCompanyFilingHistory",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "category",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 203
          },
          {
            "name": "companyNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "itemsPerPage",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 25
            },
            "x-order": 400
          },
          {
            "name": "startIndex",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 0
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FilingHistoryItemPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/companies-house/{companyNumber}/filing-history/{transactionId}": {
      "get": {
        "tags": [
          "Companies House"
        ],
        "summary": "Get Filing Details",
        "description": "Retrieve detailed information about a specific filing",
        "operationId": "GetCompanyFiling",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "companyNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "transactionId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FilingHistoryItem"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/companies-house/{companyNumber}/documents/{documentId}": {
      "get": {
        "tags": [
          "Companies House"
        ],
        "summary": "Get Document",
        "description": "Retrieve a specific document from Companies House",
        "operationId": "GetCompanyDocument",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "companyNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "documentId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/contacts": {
      "get": {
        "tags": [
          "Contacts"
        ],
        "summary": "List Contacts",
        "description": "Lists all Contacts for the given tenant.",
        "operationId": "ListContacts",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/ContactSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "clientCode",
            "in": "query",
            "description": "Filter by client code - only show contacts associated with this client",
            "schema": {
              "type": "string",
              "example": "CLI001"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search across contact details: code, name, email, phone (minimum 3 characters)",
            "schema": {
              "type": "string",
              "example": "john"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Contacts"
        ],
        "summary": "Create Contact",
        "description": "Creates a new Contact for the specified tenant.",
        "operationId": "CreateContact",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateContactRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/contacts/{code}": {
      "get": {
        "tags": [
          "Contacts"
        ],
        "summary": "Get Contact",
        "description": "Gets a Contact for the specified tenant.",
        "operationId": "GetContact",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Contacts"
        ],
        "summary": "Update Contact",
        "description": "Updates a Contact for the specified tenant.",
        "operationId": "UpdateContact",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateContactRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Contacts"
        ],
        "summary": "Delete Contact",
        "description": "Deletes a Contact for the specified tenant.",
        "operationId": "DeleteContact",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/contacts/{code}/clients": {
      "get": {
        "tags": [
          "Contacts"
        ],
        "summary": "List Contact Clients",
        "description": "Returns a list of clients that have the specified contact associated with them",
        "operationId": "GetClientsForContact",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ClientContactDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/contentblocks": {
      "get": {
        "tags": [
          "Content Blocks"
        ],
        "summary": "List ContentBlocks",
        "description": "Lists all ContentBlocks for the given tenant.",
        "operationId": "ListContentBlocks",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/ContentBlockSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "category",
            "in": "query",
            "description": "Filter content blocks by category",
            "schema": {
              "enum": [
                "Custom",
                "ServiceTerms",
                "ServiceProposals",
                "TemplateParts",
                "WebContent",
                "Email",
                "EmailParts"
              ],
              "type": "string",
              "example": "Custom"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search across content block code and name (minimum 3 characters)",
            "schema": {
              "type": "string",
              "example": "footer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContentBlockDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Content Blocks"
        ],
        "summary": "Create ContentBlock",
        "description": "Creates a new ContentBlock for the specified tenant.",
        "operationId": "CreateContentBlock",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateContentBlockRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContentBlockDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/contentblocks/{code}": {
      "get": {
        "tags": [
          "Content Blocks"
        ],
        "summary": "Get ContentBlock",
        "description": "Gets a ContentBlock for the specified tenant.",
        "operationId": "GetContentBlock",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContentBlockDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Content Blocks"
        ],
        "summary": "Update ContentBlock",
        "description": "Updates a ContentBlock for the specified tenant.",
        "operationId": "UpdateContentBlock",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateContentBlockRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContentBlockDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Content Blocks"
        ],
        "summary": "Delete ContentBlock",
        "description": "Deletes a ContentBlock for the specified tenant.",
        "operationId": "DeleteContentBlock",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/contentblocks/library": {
      "get": {
        "tags": [
          "Content Blocks"
        ],
        "summary": "List Library ContentBlocks",
        "description": "List all ContentBlocks available in the library as templates. Use optional 'search' query parameter to filter by Code, Name, or Description.",
        "operationId": "ListLibraryContentBlocks",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 150
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ContentBlockDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/contentblocks/library/{code}": {
      "get": {
        "tags": [
          "Content Blocks"
        ],
        "summary": "Get Library ContentBlock",
        "description": "Get details of a specific ContentBlock template from the library",
        "operationId": "GetLibraryContentBlock",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContentBlockDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/contentblocks/{code}/library-version": {
      "put": {
        "tags": [
          "Content Blocks"
        ],
        "summary": "Revert ContentBlock to Library",
        "description": "Reverts the ContentBlock to the current library template version, overwriting any local edits. The ContentBlock's code is preserved so it remains addressable at the same URL. Returns 400 if the ContentBlock was not imported from the library, or 404 if the ContentBlock or its source library template no longer exists.",
        "operationId": "RevertContentBlockToLibraryVersion",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContentBlockDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/contentblocks/template-variables": {
      "get": {
        "tags": [
          "Content Blocks"
        ],
        "summary": "Get Template Variables",
        "description": "Returns template variables for content block rendering. When a clientCode is provided, variables are populated with client, partner, manager, practice, contacts, key dates, and custom fields. Otherwise only practice details are included.",
        "operationId": "GetContentBlockTemplateVariables",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "clientCode",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 213
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TemplateVariables"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/contentblocks/{code}/render": {
      "post": {
        "tags": [
          "Content Blocks"
        ],
        "summary": "Render Content Block",
        "description": "Renders a content block's body HTML with Liquid tokens resolved using the provided template variables. When includeEmailBranding is true, wraps the result with the tenant's email header, footer, and design theme. Returns the rendered HTML string.",
        "operationId": "RenderContentBlock",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RenderContentBlockRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "get": {
        "tags": [
          "Content Blocks"
        ],
        "summary": "Preview Content Block",
        "description": "Renders a content block by code with template variables built server-side. When clientCode is supplied, hydrates client/business/contacts/practice/key dates/custom fields. Otherwise renders with practice details and date/year tokens only. Returns text/html so the response can be opened directly in a browser.",
        "operationId": "PreviewContentBlock",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          },
          {
            "name": "clientCode",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 213
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/contentblocks/render-template": {
      "post": {
        "tags": [
          "Content Blocks"
        ],
        "summary": "Render Template String",
        "description": "Renders an arbitrary Liquid template string (e.g. a subject line) with the provided template variables. Returns the rendered string.",
        "operationId": "RenderTemplateString",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RenderTemplateStringRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/csv-mappings": {
      "get": {
        "tags": [
          "CSV Mappings"
        ],
        "summary": "List CsvMappings",
        "description": "Lists all CsvMappings for the given tenant.",
        "operationId": "ListCsvMappings",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/CsvMappingSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "mappingType",
            "in": "query",
            "description": "Filter by mapping type",
            "schema": {
              "enum": [
                "Client"
              ],
              "type": "string",
              "example": "Client"
            }
          },
          {
            "name": "isPreset",
            "in": "query",
            "description": "Filter by preset mappings",
            "schema": {
              "type": "boolean",
              "example": "true"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search across mapping name (minimum 3 characters)",
            "schema": {
              "type": "string",
              "example": "limited company"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CsvMappingDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "CSV Mappings"
        ],
        "summary": "Create CsvMapping",
        "description": "Creates a new CsvMapping for the specified tenant.",
        "operationId": "CreateCsvMapping",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCsvMappingRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CsvMappingDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/csv-mappings/{code}": {
      "get": {
        "tags": [
          "CSV Mappings"
        ],
        "summary": "Get CsvMapping",
        "description": "Gets a CsvMapping for the specified tenant.",
        "operationId": "GetCsvMapping",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CsvMappingDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "CSV Mappings"
        ],
        "summary": "Update CsvMapping",
        "description": "Updates a CsvMapping for the specified tenant.",
        "operationId": "UpdateCsvMapping",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCsvMappingRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CsvMappingDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "CSV Mappings"
        ],
        "summary": "Delete CsvMapping",
        "description": "Deletes a CsvMapping for the specified tenant.",
        "operationId": "DeleteCsvMapping",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/custom-field-groups": {
      "get": {
        "tags": [
          "Custom Field Groups"
        ],
        "summary": "List CustomFieldGroups",
        "description": "Lists all CustomFieldGroups for the given tenant.",
        "operationId": "ListCustomFieldGroups",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/CustomFieldGroupSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "entityType",
            "in": "query",
            "description": "Filter by entity type",
            "schema": {
              "enum": [
                "Client"
              ],
              "type": "string",
              "example": "Client"
            }
          },
          {
            "name": "clientType",
            "in": "query",
            "description": "Only return groups that contain at least one active field applicable to this client type",
            "schema": {
              "enum": [
                "PrivateLimitedCompany",
                "PublicLimitedCompany",
                "LimitedLiabilityPartnership",
                "Partnership",
                "Individual",
                "Trust",
                "Charity",
                "SoleTrader"
              ],
              "type": "string",
              "example": "PrivateLimitedCompany"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomFieldGroupDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Custom Field Groups"
        ],
        "summary": "Create CustomFieldGroup",
        "description": "Creates a new CustomFieldGroup for the specified tenant.",
        "operationId": "CreateCustomFieldGroup",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCustomFieldGroupRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomFieldGroupDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/custom-field-groups/{code}": {
      "get": {
        "tags": [
          "Custom Field Groups"
        ],
        "summary": "Get CustomFieldGroup",
        "description": "Gets a CustomFieldGroup for the specified tenant.",
        "operationId": "GetCustomFieldGroup",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomFieldGroupDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Custom Field Groups"
        ],
        "summary": "Update CustomFieldGroup",
        "description": "Updates a CustomFieldGroup for the specified tenant.",
        "operationId": "UpdateCustomFieldGroup",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCustomFieldGroupRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomFieldGroupDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Custom Field Groups"
        ],
        "summary": "Delete CustomFieldGroup",
        "description": "Deletes a CustomFieldGroup for the specified tenant.",
        "operationId": "DeleteCustomFieldGroup",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/custom-fields": {
      "get": {
        "tags": [
          "Custom Fields"
        ],
        "summary": "List CustomFieldDefinitions",
        "description": "Lists all CustomFieldDefinitions for the given tenant.",
        "operationId": "ListCustomFieldDefinitions",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/CustomFieldDefinitionSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "entityType",
            "in": "query",
            "description": "Filter by entity type",
            "schema": {
              "enum": [
                "Client"
              ],
              "type": "string",
              "example": "Client"
            }
          },
          {
            "name": "dataType",
            "in": "query",
            "description": "Filter by data type",
            "schema": {
              "enum": [
                "Text",
                "Number",
                "Date",
                "Boolean",
                "Select",
                "MultiSelect",
                "TextArea",
                "Address",
                "Email",
                "File"
              ],
              "type": "string",
              "example": "Date"
            }
          },
          {
            "name": "clientType",
            "in": "query",
            "description": "Filter by applicable client type. Returns fields that explicitly include this type, or have no types specified (applicable to all).",
            "schema": {
              "enum": [
                "PrivateLimitedCompany",
                "PublicLimitedCompany",
                "LimitedLiabilityPartnership",
                "Partnership",
                "Individual",
                "Trust",
                "Charity",
                "SoleTrader"
              ],
              "type": "string",
              "example": "PrivateLimitedCompany"
            }
          },
          {
            "name": "isArchived",
            "in": "query",
            "description": "Filter by archived status (true = archived only, false = active only)",
            "schema": {
              "type": "boolean",
              "example": "false"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search across field code and label (minimum 3 characters)",
            "schema": {
              "type": "string",
              "example": "company"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomFieldDefinitionDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Custom Fields"
        ],
        "summary": "Create CustomFieldDefinition",
        "description": "Creates a new CustomFieldDefinition for the specified tenant.",
        "operationId": "CreateCustomFieldDefinition",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCustomFieldDefinitionRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomFieldDefinitionDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/custom-fields/{code}": {
      "get": {
        "tags": [
          "Custom Fields"
        ],
        "summary": "Get CustomFieldDefinition",
        "description": "Gets a CustomFieldDefinition for the specified tenant.",
        "operationId": "GetCustomFieldDefinition",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomFieldDefinitionDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Custom Fields"
        ],
        "summary": "Update CustomFieldDefinition",
        "description": "Updates a CustomFieldDefinition for the specified tenant.",
        "operationId": "UpdateCustomFieldDefinition",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCustomFieldDefinitionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomFieldDefinitionDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Custom Fields"
        ],
        "summary": "Delete CustomFieldDefinition",
        "description": "Deletes a CustomFieldDefinition for the specified tenant.",
        "operationId": "DeleteCustomFieldDefinition",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/custom-tokens": {
      "get": {
        "tags": [
          "Custom Tokens"
        ],
        "summary": "List CustomTokens",
        "description": "Lists all CustomTokens for the given tenant.",
        "operationId": "ListCustomTokens",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/CustomTokenSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search term to filter results",
            "schema": {
              "type": "string",
              "example": "keyword"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomTokenDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Custom Tokens"
        ],
        "summary": "Create CustomToken",
        "description": "Creates a new CustomToken for the specified tenant.",
        "operationId": "CreateCustomToken",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCustomTokenRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomTokenDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/custom-tokens/{code}": {
      "get": {
        "tags": [
          "Custom Tokens"
        ],
        "summary": "Get CustomToken",
        "description": "Gets a CustomToken for the specified tenant.",
        "operationId": "GetCustomToken",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomTokenDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Custom Tokens"
        ],
        "summary": "Update CustomToken",
        "description": "Updates a CustomToken for the specified tenant.",
        "operationId": "UpdateCustomToken",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCustomTokenRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomTokenDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Custom Tokens"
        ],
        "summary": "Delete CustomToken",
        "description": "Deletes a CustomToken for the specified tenant.",
        "operationId": "DeleteCustomToken",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/data-form-categories": {
      "get": {
        "tags": [
          "Data Form - Categories"
        ],
        "summary": "List DataFormCategories",
        "description": "Lists all DataFormCategories for the given tenant.",
        "operationId": "ListDataFormCategories",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/DataFormCategorySortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search term to filter results",
            "schema": {
              "type": "string",
              "example": "keyword"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataFormCategoryDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Data Form - Categories"
        ],
        "summary": "Create DataFormCategory",
        "description": "Creates a new DataFormCategory for the specified tenant.",
        "operationId": "CreateDataFormCategory",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateDataFormCategoryRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataFormCategoryDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/data-form-categories/{code}": {
      "get": {
        "tags": [
          "Data Form - Categories"
        ],
        "summary": "Get DataFormCategory",
        "description": "Gets a DataFormCategory for the specified tenant.",
        "operationId": "GetDataFormCategory",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataFormCategoryDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Data Form - Categories"
        ],
        "summary": "Update DataFormCategory",
        "description": "Updates a DataFormCategory for the specified tenant.",
        "operationId": "UpdateDataFormCategory",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateDataFormCategoryRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataFormCategoryDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Data Form - Categories"
        ],
        "summary": "Delete DataFormCategory",
        "description": "Deletes a DataFormCategory for the specified tenant.",
        "operationId": "DeleteDataFormCategory",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/data-form-requests": {
      "get": {
        "tags": [
          "Data Form - Requests"
        ],
        "summary": "List DataFormRequests",
        "description": "Lists all DataFormRequests for the given tenant.",
        "operationId": "ListDataFormRequests",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/DataFormRequestSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter by request status (Pending, Submitted, Accepted, Rejected)",
            "schema": {
              "enum": [
                "PendingResponse",
                "ResponseReceived"
              ],
              "type": "string",
              "example": "Pending"
            }
          },
          {
            "name": "clientCode",
            "in": "query",
            "description": "Filter by client code",
            "schema": {
              "type": "string",
              "example": "client-abc"
            }
          },
          {
            "name": "formCode",
            "in": "query",
            "description": "Filter by form code",
            "schema": {
              "type": "string",
              "example": "form-abc"
            }
          },
          {
            "name": "categoryCode",
            "in": "query",
            "description": "Filter by form category code",
            "schema": {
              "type": "string",
              "example": "onboarding"
            }
          },
          {
            "name": "managerCode",
            "in": "query",
            "description": "Filter by client manager user code",
            "schema": {
              "type": "string",
              "example": "USR001"
            }
          },
          {
            "name": "partnerCode",
            "in": "query",
            "description": "Filter by client partner user code",
            "schema": {
              "type": "string",
              "example": "USR002"
            }
          },
          {
            "name": "taskCategoryCode",
            "in": "query",
            "description": "Filter by task category code",
            "schema": {
              "type": "string",
              "example": "CAT001"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search term to filter results",
            "schema": {
              "type": "string",
              "example": "keyword"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataFormRequestDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/data-form-requests/{code}": {
      "get": {
        "tags": [
          "Data Form - Requests"
        ],
        "summary": "Get DataFormRequest",
        "description": "Gets a DataFormRequest for the specified tenant.",
        "operationId": "GetDataFormRequest",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataFormRequestDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Data Form - Requests"
        ],
        "summary": "Update DataFormRequest",
        "description": "Updates a DataFormRequest for the specified tenant.",
        "operationId": "UpdateDataFormRequest",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DataFormRequestDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataFormRequestDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Data Form - Requests"
        ],
        "summary": "Delete DataFormRequest",
        "description": "Deletes a DataFormRequest for the specified tenant.",
        "operationId": "DeleteDataFormRequest",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/data-form-requests/{code}/answers/{questionCode}/review": {
      "put": {
        "tags": [
          "Data Form - Requests"
        ],
        "summary": "Review DataForm Answer",
        "description": "Accepts or rejects a single answer on a submitted form request. When accepted, applies the value to the client record.",
        "operationId": "ReviewDataFormAnswer",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          },
          {
            "name": "questionCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReviewDataFormAnswerRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataFormRequestDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/data-form-requests/{code}/resend": {
      "put": {
        "tags": [
          "Data Form - Requests"
        ],
        "summary": "Resend DataForm Request",
        "description": "Resends the notification email for a pending form request to the specified recipients.",
        "operationId": "ResendDataFormRequest",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResendDataFormRequestRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataFormRequestDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/data-forms": {
      "get": {
        "tags": [
          "Data Forms"
        ],
        "summary": "List DataForms",
        "description": "Lists all DataForms for the given tenant.",
        "operationId": "ListDataForms",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/DataFormSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter by form status (Draft, Published, Archived)",
            "schema": {
              "enum": [
                "Draft",
                "Published",
                "Archived"
              ],
              "type": "string",
              "example": "Published"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search term to filter results",
            "schema": {
              "type": "string",
              "example": "keyword"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataFormDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Data Forms"
        ],
        "summary": "Create DataForm",
        "description": "Creates a new DataForm for the specified tenant.",
        "operationId": "CreateDataForm",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateDataFormRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataFormDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/data-forms/{code}": {
      "get": {
        "tags": [
          "Data Forms"
        ],
        "summary": "Get DataForm",
        "description": "Gets a DataForm for the specified tenant.",
        "operationId": "GetDataForm",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataFormDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Data Forms"
        ],
        "summary": "Update DataForm",
        "description": "Updates a DataForm for the specified tenant.",
        "operationId": "UpdateDataForm",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateDataFormRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataFormDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Data Forms"
        ],
        "summary": "Delete DataForm",
        "description": "Deletes a DataForm for the specified tenant.",
        "operationId": "DeleteDataForm",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/data-forms/library": {
      "get": {
        "tags": [
          "Data Forms"
        ],
        "summary": "List Library DataForms",
        "description": "List all DataForms available in the library as templates. Use optional 'search' query parameter to filter by Code, Name, or Description.",
        "operationId": "ListLibraryDataForms",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 150
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/DataFormDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/data-forms/library/{code}": {
      "get": {
        "tags": [
          "Data Forms"
        ],
        "summary": "Get Library DataForm",
        "description": "Get details of a specific DataForm template from the library",
        "operationId": "GetLibraryDataForm",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataFormDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/data-forms/{code}/library-version": {
      "put": {
        "tags": [
          "Data Forms"
        ],
        "summary": "Revert DataForm to Library",
        "description": "Reverts the DataForm to the current library template version, overwriting any local edits. The DataForm's code is preserved so it remains addressable at the same URL. Returns 400 if the DataForm was not imported from the library, or 404 if the DataForm or its source library template no longer exists.",
        "operationId": "RevertDataFormToLibraryVersion",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataFormDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/data-forms/library/{libraryCode}/create": {
      "post": {
        "tags": [
          "Data Forms"
        ],
        "summary": "Create DataForm from Library",
        "description": "Creates a new DataForm for the tenant based on a library template. Automatically creates the form category if it doesn't exist. Re-imports of the same library item are supported and produce a fresh row with the supplied NameSuffix appended (or auto '(N)' when omitted).",
        "operationId": "CreateDataFormFromLibrary",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "libraryCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImportFromLibraryRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataFormDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/data-forms/{code}/send": {
      "post": {
        "tags": [
          "Data Forms"
        ],
        "summary": "Send DataForm to Client",
        "description": "Sends a published form to a single client, creating a form request and sending a notification email.",
        "operationId": "SendDataFormToClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendDataFormRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataFormRequestDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/data-forms/{code}/send-bulk": {
      "post": {
        "tags": [
          "Data Forms"
        ],
        "summary": "Send DataForm to Multiple Clients",
        "description": "Sends a published form to multiple clients in bulk.",
        "operationId": "BulkSendDataForm",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkSendDataFormRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/data-forms/convert": {
      "post": {
        "tags": [
          "Data Forms"
        ],
        "summary": "Convert Form File",
        "description": "Converts an external form definition file (e.g. Engager .cexp) into Sodium's import format.",
        "operationId": "ConvertFormFile",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConvertFormFileRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConvertFormFileResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/data-forms/{code}/client-preview": {
      "post": {
        "tags": [
          "Data Forms"
        ],
        "summary": "Create Client Preview Link",
        "description": "Creates a short-lived (5 min) portal URL for staff to preview the form exactly as a specific client would see it. Access is gated by client visibility restrictions.",
        "operationId": "CreateDataFormClientPreview",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClientPreviewDataFormRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateDataFormPreviewTokenResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/data-forms/{code}/preview": {
      "get": {
        "tags": [
          "Data Forms"
        ],
        "summary": "Preview DataForm",
        "description": "Returns the form structure as the client would see it, for preview purposes.",
        "operationId": "PreviewDataForm",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DataFormPreviewDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/designthemes/{designThemeCode}/backgroundimages": {
      "get": {
        "tags": [
          "Design Theme - Background Images"
        ],
        "summary": "List Background Images",
        "description": "Returns all background images configured on the specified design theme, ordered by sort order.",
        "operationId": "ListDesignThemeBackgroundImages",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "designThemeCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/BackgroundImageDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "post": {
        "tags": [
          "Design Theme - Background Images"
        ],
        "summary": "Add Background Image",
        "description": "Adds a new background image to the specified design theme.",
        "operationId": "AddDesignThemeBackgroundImage",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "designThemeCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BackgroundImageRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BackgroundImageDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/designthemes/{designThemeCode}/backgroundimages/{imageCode}": {
      "put": {
        "tags": [
          "Design Theme - Background Images"
        ],
        "summary": "Update Background Image",
        "description": "Updates an existing background image on the specified design theme.",
        "operationId": "UpdateDesignThemeBackgroundImage",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "designThemeCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "imageCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BackgroundImageRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BackgroundImageDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Design Theme - Background Images"
        ],
        "summary": "Delete Background Image",
        "description": "Removes a background image from the specified design theme.",
        "operationId": "DeleteDesignThemeBackgroundImage",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "designThemeCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "imageCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/designthemes": {
      "get": {
        "tags": [
          "Design Themes"
        ],
        "summary": "List DesignThemes",
        "description": "Lists all DesignThemes for the given tenant.",
        "operationId": "ListDesignThemes",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/DesignThemeSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search term to filter results",
            "schema": {
              "type": "string",
              "example": "keyword"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DesignThemeDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Design Themes"
        ],
        "summary": "Create DesignTheme",
        "description": "Creates a new DesignTheme for the specified tenant.",
        "operationId": "CreateDesignTheme",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateDesignThemeRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DesignThemeDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/designthemes/{code}": {
      "get": {
        "tags": [
          "Design Themes"
        ],
        "summary": "Get DesignTheme",
        "description": "Gets a DesignTheme for the specified tenant.",
        "operationId": "GetDesignTheme",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DesignThemeDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Design Themes"
        ],
        "summary": "Update DesignTheme",
        "description": "Updates a DesignTheme for the specified tenant.",
        "operationId": "UpdateDesignTheme",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateDesignThemeRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DesignThemeDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Design Themes"
        ],
        "summary": "Delete DesignTheme",
        "description": "Deletes a DesignTheme for the specified tenant.",
        "operationId": "DeleteDesignTheme",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/designthemes/default": {
      "get": {
        "tags": [
          "Design Themes"
        ],
        "summary": "Get Default Design Theme",
        "description": "Returns the default design theme for the specified tenant.",
        "operationId": "GetDefaultDesignTheme",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DesignThemeDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/designthemes/{code}/css": {
      "get": {
        "tags": [
          "Design Themes"
        ],
        "summary": "Get Design Theme CSS",
        "description": "Returns the generated CSS for the specified design theme.",
        "operationId": "GetDesignThemeCSS",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          },
          {
            "name": "selector",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/css": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/designthemes/default/css": {
      "get": {
        "tags": [
          "Design Themes"
        ],
        "summary": "Get Default Design Theme CSS",
        "description": "Returns the generated CSS for the default design theme.",
        "operationId": "GetDefaultDesignThemeCSS",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "selector",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/css": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/direct-debit/payers": {
      "get": {
        "tags": [
          "DirectDebit"
        ],
        "summary": "List DirectDebit Payers",
        "description": "Lists all payers (customers) from the direct debit platform",
        "operationId": "GetDirectDebitPayers",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PayerDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/direct-debit/mandates": {
      "get": {
        "tags": [
          "DirectDebit"
        ],
        "summary": "List DirectDebit Mandates",
        "description": "Lists mandates from the direct debit platform for a specific payer. Requires payerId.",
        "operationId": "GetDirectDebitMandates",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "payerId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/MandateDto"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/direct-debit/mandates/{mandateId}": {
      "get": {
        "tags": [
          "DirectDebit"
        ],
        "summary": "Get DirectDebit Mandate",
        "description": "Gets a specific mandate to check its status",
        "operationId": "GetDirectDebitMandateById",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "mandateId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MandateDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/direct-debit/setup/send-email": {
      "post": {
        "tags": [
          "DirectDebit"
        ],
        "summary": "Send Direct Debit Setup Email",
        "description": "Sends an email to the client asking them to complete the Direct Debit setup process. Includes a {Url} for them to visit. The ContentBlock for the email is set in the DirectDebitSettings",
        "operationId": "SendDirectDebitSetupEmail",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendDirectDebitSetupEmailRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/direct-debit/setup/callback": {
      "get": {
        "tags": [
          "DirectDebit"
        ],
        "summary": "Complete Direct Debit Setup",
        "description": "Callback endpoint for completing direct debit mandate setup after customer authorization. The DirectDebit provider will redirect the user here after they set up a mandate. We will then redirect the user to the URl provided as the callbackUrl in the initial SendDirectDebitSetupEmailRequest",
        "operationId": "CompleteDirectDebitSetup",
        "parameters": [
          {
            "name": "code",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/tenants/{tenant}/direct-debit/settings": {
      "get": {
        "tags": [
          "DirectDebit"
        ],
        "summary": "Get Direct Debit Settings",
        "description": "Returns the direct debit settings for the specified tenant",
        "operationId": "GetDirectDebitSettings",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DirectDebitSettingsDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "put": {
        "tags": [
          "DirectDebit"
        ],
        "summary": "Update Direct Debit Settings",
        "description": "Updates the direct debit settings for the specified tenant",
        "operationId": "UpdateDirectDebitSettings",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateDirectDebitSettingsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DirectDebitSettingsDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/documentrequests": {
      "get": {
        "tags": [
          "Document Requests"
        ],
        "summary": "List Document Requests",
        "description": "Returns a paged list of document requests across all clients.",
        "operationId": "ListAllDocumentRequests",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/DocumentRequestSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter by request status (Draft, Open, Submitted, Accepted, Rejected, Cancelled)",
            "schema": {
              "enum": [
                "Draft",
                "Open",
                "Submitted",
                "Accepted",
                "Rejected"
              ],
              "type": "string",
              "example": "Open"
            }
          },
          {
            "name": "clientCode",
            "in": "query",
            "description": "Filter by client code",
            "schema": {
              "type": "string",
              "example": "acme-ltd"
            }
          },
          {
            "name": "managerCode",
            "in": "query",
            "description": "Filter by client manager user code",
            "schema": {
              "type": "string",
              "example": "USR001"
            }
          },
          {
            "name": "partnerCode",
            "in": "query",
            "description": "Filter by client partner user code",
            "schema": {
              "type": "string",
              "example": "USR002"
            }
          },
          {
            "name": "taskCategoryCode",
            "in": "query",
            "description": "Filter by task category code",
            "schema": {
              "type": "string",
              "example": "CAT001"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search across request title and description (minimum 3 characters)",
            "schema": {
              "type": "string",
              "example": "tax returns"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentRequestDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/document-templates": {
      "get": {
        "tags": [
          "Document Templates"
        ],
        "summary": "List DocumentTemplates",
        "description": "Lists all DocumentTemplates for the given tenant.",
        "operationId": "ListDocumentTemplates",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/DocumentTemplateSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "type",
            "in": "query",
            "description": "Filter by template type",
            "schema": {
              "enum": [
                "EngagementLetter",
                "Proposal",
                "AdHoc"
              ],
              "type": "string",
              "example": "EngagementLetter"
            }
          },
          {
            "name": "isActive",
            "in": "query",
            "description": "Filter by active status (true = active only, false = inactive only)",
            "schema": {
              "type": "boolean",
              "example": "true"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search across template code and name (minimum 3 characters)",
            "schema": {
              "type": "string",
              "example": "engagement"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentTemplateDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Document Templates"
        ],
        "summary": "Create DocumentTemplate",
        "description": "Creates a new DocumentTemplate for the specified tenant.",
        "operationId": "CreateDocumentTemplate",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateDocumentTemplateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentTemplateDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/document-templates/{code}": {
      "get": {
        "tags": [
          "Document Templates"
        ],
        "summary": "Get DocumentTemplate",
        "description": "Gets a DocumentTemplate for the specified tenant.",
        "operationId": "GetDocumentTemplate",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentTemplateDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Document Templates"
        ],
        "summary": "Update DocumentTemplate",
        "description": "Updates a DocumentTemplate for the specified tenant.",
        "operationId": "UpdateDocumentTemplate",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateDocumentTemplateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentTemplateDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Document Templates"
        ],
        "summary": "Delete DocumentTemplate",
        "description": "Deletes a DocumentTemplate for the specified tenant.",
        "operationId": "DeleteDocumentTemplate",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/document-templates/library": {
      "get": {
        "tags": [
          "Document Templates"
        ],
        "summary": "List Library DocumentTemplates",
        "description": "List all DocumentTemplates available in the library as templates. Use optional 'search' query parameter to filter by Code, Name, or Description.",
        "operationId": "ListLibraryDocumentTemplates",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 150
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/DocumentTemplateDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/document-templates/library/{code}": {
      "get": {
        "tags": [
          "Document Templates"
        ],
        "summary": "Get Library DocumentTemplate",
        "description": "Get details of a specific DocumentTemplate template from the library",
        "operationId": "GetLibraryDocumentTemplate",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentTemplateDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/document-templates/{code}/library-version": {
      "put": {
        "tags": [
          "Document Templates"
        ],
        "summary": "Revert DocumentTemplate to Library",
        "description": "Reverts the DocumentTemplate to the current library template version, overwriting any local edits. The DocumentTemplate's code is preserved so it remains addressable at the same URL. Returns 400 if the DocumentTemplate was not imported from the library, or 404 if the DocumentTemplate or its source library template no longer exists.",
        "operationId": "RevertDocumentTemplateToLibraryVersion",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentTemplateDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/document-templates/{code}/render": {
      "post": {
        "tags": [
          "Document Templates"
        ],
        "summary": "Render DocumentTemplate as PDF",
        "description": "Renders a document template with the provided data to PDF format.\n\nThe template receives the TemplateVariables data structure from the request.\nAll properties are optional and accessible via Liquid syntax (e.g., {{ PrimaryContact.FirstName }})\n\n**Example request:**\n```json\nPOST /tenants/acme/document-templates/engagement-letter-standard/render\n{\n  \"designThemeCode\": \"professional-blue\",\n  \"data\": {\n    \"title\": \"Engagement Letter\",\n    \"client\": {\n      \"primaryContact\": { \"firstName\": \"John\", \"lastName\": \"Doe\" },\n      \"partner\": { \"name\": \"Jane Smith\", \"email\": \"jane@example.com\" }\n    },\n    \"practice\": {\n      \"address\": \"123 Main St\",\n      \"email\": \"info@practice.com\",\n      \"telephone\": \"555-1234\"\n    }\n  }\n}\n```",
        "operationId": "RenderDocumentTemplate",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RenderDocumentTemplateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/document-templates/library/{libraryCode}/import": {
      "post": {
        "tags": [
          "Document Templates"
        ],
        "summary": "Import from Library",
        "description": "Imports a document template from the library, creating any associated custom tokens that don't already exist. Re-imports of the same library item are supported and produce a fresh row with the supplied NameSuffix appended (or auto '(N)' when omitted).",
        "operationId": "ImportDocumentTemplateFromLibrary",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "libraryCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImportFromLibraryRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentTemplateDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/document-templates/{code}/custom-tokens": {
      "get": {
        "tags": [
          "Document Templates"
        ],
        "summary": "Get Custom Tokens",
        "description": "Extracts custom token names from a document template's body HTML, excluding standard template variables.",
        "operationId": "GetDocumentTemplateCustomTokens",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          },
          {
            "name": "clientCode",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 213
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/DocumentTemplateTokenInfo"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/document-categories": {
      "get": {
        "tags": [
          "Documents - Categories"
        ],
        "summary": "List DocumentCategories",
        "description": "Lists all DocumentCategories for the given tenant.",
        "operationId": "ListDocumentCategories",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/DocumentCategorySortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search term to filter results",
            "schema": {
              "type": "string",
              "example": "keyword"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentCategoryDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Documents - Categories"
        ],
        "summary": "Create DocumentCategory",
        "description": "Creates a new DocumentCategory for the specified tenant.",
        "operationId": "CreateDocumentCategory",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateDocumentCategoryRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentCategoryDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/document-categories/{code}": {
      "get": {
        "tags": [
          "Documents - Categories"
        ],
        "summary": "Get DocumentCategory",
        "description": "Gets a DocumentCategory for the specified tenant.",
        "operationId": "GetDocumentCategory",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentCategoryDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Documents - Categories"
        ],
        "summary": "Update DocumentCategory",
        "description": "Updates a DocumentCategory for the specified tenant.",
        "operationId": "UpdateDocumentCategory",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateDocumentCategoryRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentCategoryDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Documents - Categories"
        ],
        "summary": "Delete DocumentCategory",
        "description": "Deletes a DocumentCategory for the specified tenant.",
        "operationId": "DeleteDocumentCategory",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/email-broadcasts": {
      "get": {
        "tags": [
          "Email - Broadcasts"
        ],
        "summary": "List Email Broadcasts",
        "description": "Returns a paged list of email broadcasts for the tenant, newest first. Filter by status.",
        "operationId": "ListEmailBroadcasts",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/EmailBroadcastSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter by broadcast status (Draft, Queued, Sending, Completed, Failed, Cancelled)",
            "schema": {
              "enum": [
                "Draft",
                "Queued",
                "Sending",
                "Completed",
                "Failed",
                "Cancelled"
              ],
              "type": "string",
              "example": "Draft"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailBroadcastDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Email - Broadcasts"
        ],
        "summary": "Create Email Broadcast",
        "description": "Creates a draft email broadcast. Content is either a content block (category: Email) or an inline subject and body with Liquid tokens — not both. Recipient selection combines an optional client filter with hand-picked additions and exclusions. Requires the tenant to have connected at least one of their own send-enabled email accounts — broadcasts cannot be sent from the shared system mailbox.",
        "operationId": "CreateEmailBroadcast",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateEmailBroadcastRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailBroadcastDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/email-broadcasts/audience-summary": {
      "post": {
        "tags": [
          "Email - Broadcasts"
        ],
        "summary": "Summarise Broadcast Audience",
        "description": "Evaluates a client selection (saved view or inline filter, plus additions and exclusions) and returns how many clients it resolves to and how many of those have not opted in to email contact. When a To-recipient configuration is included, also counts clients with no resolvable email address. Read-only — used by the wizard before a draft exists.",
        "operationId": "GetEmailBroadcastAudienceSummary",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmailBroadcastAudienceRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailBroadcastAudienceSummaryDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/email-broadcasts/{code}": {
      "get": {
        "tags": [
          "Email - Broadcasts"
        ],
        "summary": "Get Email Broadcast",
        "description": "Returns a single email broadcast including its status and progress counters.",
        "operationId": "GetEmailBroadcast",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailBroadcastDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Email - Broadcasts"
        ],
        "summary": "Update Email Broadcast",
        "description": "Updates a draft email broadcast (full replacement). Once queued, a broadcast is immutable — only cancel is available.",
        "operationId": "UpdateEmailBroadcast",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateEmailBroadcastRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailBroadcastDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Email - Broadcasts"
        ],
        "summary": "Delete Email Broadcast",
        "description": "Deletes a draft email broadcast. Sent broadcasts cannot be deleted — they are the audit record of what was sent.",
        "operationId": "DeleteEmailBroadcast",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/email-broadcasts/{code}/recipients": {
      "get": {
        "tags": [
          "Email - Broadcasts"
        ],
        "summary": "List Broadcast Recipients",
        "description": "Returns the paged recipient list. For drafts the recipients are resolved live (pre-send view including skipped clients with reasons, e.g. no resolvable contact or email preference not set); after sending, the stored snapshot with per-client delivery status is returned.",
        "operationId": "GetEmailBroadcastRecipients",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/EmailBroadcastRecipientSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailBroadcastRecipientDtoPagedResult"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/email-broadcasts/{code}/preview/{clientCode}": {
      "get": {
        "tags": [
          "Email - Broadcasts"
        ],
        "summary": "Preview Broadcast Email",
        "description": "Renders the broadcast subject and body for the sample client identified by clientCode with Liquid tokens resolved and tenant branding applied, plus the client's resolved recipients.",
        "operationId": "PreviewEmailBroadcast",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          },
          {
            "name": "clientCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 213
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailBroadcastPreviewDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/email-broadcasts/{code}/test": {
      "post": {
        "tags": [
          "Email - Broadcasts"
        ],
        "summary": "Send Test Email",
        "description": "Renders the broadcast for the sample client in the request body and sends it to the current user's own email address only.",
        "operationId": "SendTestEmailBroadcast",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TestEmailBroadcastRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/email-broadcasts/{code}/send": {
      "post": {
        "tags": [
          "Email - Broadcasts"
        ],
        "summary": "Send Email Broadcast",
        "description": "Sends a draft broadcast: re-evaluates the client selection, snapshots each client's resolved recipients (the audit record), marks the broadcast Queued and enqueues background processing. Poll the broadcast for progress and the recipients endpoint for the per-client delivery log.",
        "operationId": "SendEmailBroadcast",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "202": {
            "description": "Accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailBroadcastDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/email-broadcasts/{code}/cancel": {
      "post": {
        "tags": [
          "Email - Broadcasts"
        ],
        "summary": "Cancel Email Broadcast",
        "description": "Cancels a queued or sending broadcast. Recipients not yet processed remain Pending and are not sent.",
        "operationId": "CancelEmailBroadcast",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailBroadcastDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/email-configs": {
      "get": {
        "tags": [
          "Email - Configs"
        ],
        "summary": "List Email Configs",
        "description": "Returns a paginated list of email configurations the current user can access (owned or shared).",
        "operationId": "ListEmailConfigs",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/EmailConfigSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "isDefault",
            "in": "query",
            "description": "Filter by default status",
            "schema": {
              "type": "boolean",
              "example": "true"
            }
          },
          {
            "name": "isSendShared",
            "in": "query",
            "description": "Filter by send-shared status",
            "schema": {
              "type": "boolean",
              "example": "true"
            }
          },
          {
            "name": "isReadShared",
            "in": "query",
            "description": "Filter by read-shared status",
            "schema": {
              "type": "boolean",
              "example": "true"
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter by configuration lifecycle status",
            "schema": {
              "enum": [
                "PendingOAuthSetup",
                "Active",
                "OAuthFailed",
                "Deleted",
                "OAuthExpired",
                "ConnectionError",
                "Deleting"
              ],
              "type": "string",
              "example": "Active"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search term to filter results",
            "schema": {
              "type": "string",
              "example": "keyword"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailConfigDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Email - Configs"
        ],
        "summary": "Create Email Config",
        "description": "Creates a new email configuration. For SMTP: provide SmtpSettings. For OAuth (Microsoft365/Google): provide OAuthSettings with returnUrl - response includes authorisationUrl to redirect user to. If IsDefault is true, IsSendShared must also be true.",
        "operationId": "CreateEmailConfig",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateEmailConfigRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailConfigDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/email-configs/{code}": {
      "get": {
        "tags": [
          "Email - Configs"
        ],
        "summary": "Get Email Config",
        "description": "Returns a single email configuration including provider details (SMTP settings, OAuth status). User must be the owner or the config must be shared.",
        "operationId": "GetEmailConfig",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailConfigDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Email - Configs"
        ],
        "summary": "Update Email Config",
        "description": "Updates an existing email configuration. Supports updating provider settings (SMTP or OAuth), display name (FromName), and flags (IsDefault, IsSendShared, IsReadShared). User must be the owner or the config must be shared. Only the owner can change IsReadShared.",
        "operationId": "UpdateEmailConfig",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateEmailConfigRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailConfigDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Email - Configs"
        ],
        "summary": "Delete Email Config",
        "description": "Deletes an email configuration. Cannot delete the tenant's default config unless it is the only one remaining. User must be the owner or the config must be shared.",
        "operationId": "DeleteEmailConfig",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/email-configs/{code}/test": {
      "post": {
        "tags": [
          "Email - Configs"
        ],
        "summary": "Test Email Config",
        "description": "Sends a test email using the specified configuration to verify it is working correctly. User must be the owner or the config must be shared.",
        "operationId": "TestEmailConfig",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TestEmailRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TestEmailResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/email-configs/{code}/reconnect": {
      "post": {
        "tags": [
          "Email - Configs"
        ],
        "summary": "Reconnect OAuth email configuration",
        "description": "Generates a fresh OAuth authorisation URL for reconnecting an expired or incorrectly-connected email configuration. Only works for OAuth providers (Microsoft365, Google) — returns 400 for SMTP. Sets the configuration status to PendingOAuthSetup. After the user completes the OAuth flow, the configuration status returns to Active automatically. User must be the owner or the config must be shared.",
        "operationId": "ReconnectEmailConfigOAuth",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReconnectOAuthRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReconnectOAuthResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/email-history": {
      "get": {
        "tags": [
          "Email - History"
        ],
        "summary": "List Email History",
        "description": "Returns a paginated list of emails sent for the tenant. Supports filtering by status, date range, search, and metadata fields. Metadata filters use the format metadataParam=key=value (e.g., metadataParam=entityType=Proposal).",
        "operationId": "ListEmails",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/EmailSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter by email status (Queued, Sending, Sent, Delivered, Failed, Bounced)",
            "schema": {
              "enum": [
                "Queued",
                "Processing",
                "Sent",
                "Failed",
                "Cancelled"
              ],
              "type": "string",
              "example": "Sent"
            }
          },
          {
            "name": "fromDate",
            "in": "query",
            "description": "Filter by emails created on or after this date (ISO 8601 format)",
            "schema": {
              "type": "string",
              "example": "2025-01-01"
            }
          },
          {
            "name": "toDate",
            "in": "query",
            "description": "Filter by emails created on or before this date (ISO 8601 format)",
            "schema": {
              "type": "string",
              "example": "2025-12-31"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search in email subject and recipient email address",
            "schema": {
              "type": "string",
              "example": "invoice"
            }
          },
          {
            "name": "metadataParam",
            "in": "query",
            "description": "Filter by custom metadata stored with the email. Each value should be in key=value format. Can specify multiple (e.g., metadataParam=entityType=Proposal&metadataParam=entityId=123)",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"entityType=Proposal\", \"entityId=123\", \"color=red\" ]"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListEmailsResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/email-history/{emailId}": {
      "get": {
        "tags": [
          "Email - History"
        ],
        "summary": "Get Email Details",
        "description": "Returns the full details of a specific email by its ID, including recipients, attachments, and delivery status.",
        "operationId": "GetEmailDetails",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "emailId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GetMessageResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/mailbox/folders": {
      "get": {
        "tags": [
          "Email - Mailbox"
        ],
        "summary": "List Folders",
        "description": "Returns the full folder/label set across the tenant's read-enabled mailbox configurations. When configCode query param is omitted, returns folders for every accessible config (owned or shared). When configCode is provided (repeatable), narrows to those configs. Set systemFoldersOnly=true to return only provider-system folders (Inbox/Sent/Drafts/Archive/Junk/Trash/Outbox/GmailPromotionalCategory) — combined-mailbox views use this. Each folder includes per-folder total and unread counts.",
        "operationId": "ListMailboxFolders",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "configCode",
            "in": "query",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "x-order": 400
          },
          {
            "name": "systemFoldersOnly",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ExternalMailboxFolderDto"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/mailbox/conversations": {
      "get": {
        "tags": [
          "Email - Mailbox"
        ],
        "summary": "List Conversations",
        "description": "Returns a paginated list of email conversations (threads). When configCode query param is omitted, searches across mailbox configurations the current user can access (owned or shared). When configCode is provided, scopes to that single configuration. Supports filtering by direction, participant email/domain, include/exclude message IDs, and search. Pagination defaults: offset=0, limit=10, max limit=50.",
        "operationId": "ListMailboxConversations",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/MailboxConversationSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "configCode",
            "in": "query",
            "description": "Filter by configuration code (GUID, repeatable). Omit to search across all read-enabled configs.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"895c888f-c2ba-4c86-9d91-1eff95045e6a\" ]"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "description": "Filter by email direction (Inbound = received emails, Outbound = sent emails)",
            "schema": {
              "enum": [
                "Inbound",
                "Outbound"
              ],
              "type": "string",
              "example": "Inbound"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search by subject or sender email/name",
            "schema": {
              "type": "string",
              "example": "invoice"
            }
          },
          {
            "name": "participantEmail",
            "in": "query",
            "description": "Filter by participant email address - matches From, To, and Cc fields. Can specify multiple (OR logic).",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"john@example.com\", \"jane@example.com\" ]"
            }
          },
          {
            "name": "participantDomain",
            "in": "query",
            "description": "Filter by participant email domain - matches From, To, and Cc fields. Can specify multiple (OR logic).",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"example.com\", \"acme.org\" ]"
            }
          },
          {
            "name": "includeMessageId",
            "in": "query",
            "description": "Force-include specific message UniqueIds regardless of participant filters (repeatable).",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"3b39ae56-f6f4-4e6c-82c9-661a5cc366ec\" ]"
            }
          },
          {
            "name": "excludeMessageId",
            "in": "query",
            "description": "Force-exclude specific message UniqueIds even if they match participant filters (repeatable).",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"3b39ae56-f6f4-4e6c-82c9-661a5cc366ec\" ]"
            }
          },
          {
            "name": "folderUniqueId",
            "in": "query",
            "description": "Filter to messages whose junction maps to any of these folder uniqueIds (repeatable, OR logic). Single-mailbox mode. Mutually exclusive with systemFolderType.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"3b39ae56-f6f4-4e6c-82c9-661a5cc366ec\" ]"
            }
          },
          {
            "name": "systemFolderType",
            "in": "query",
            "description": "Filter to messages in folders of the given system type (Inbox/Sent/Drafts/...). Combined-mailbox mode. Mutually exclusive with folderUniqueId.",
            "schema": {
              "enum": [
                "None",
                "Inbox",
                "Sent",
                "Drafts",
                "Junk",
                "Trash",
                "Archive",
                "Outbox",
                "GmailCategory",
                "GmailPromotionalCategory"
              ],
              "type": "string",
              "example": "Inbox"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MailboxThreadSummaryDtoPagedResult"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/mailbox/messages": {
      "get": {
        "tags": [
          "Email - Mailbox"
        ],
        "summary": "List Messages",
        "description": "Returns a paginated flat list of individual messages (not grouped by thread). When configCode query param is omitted, searches across mailbox configurations the current user can access (owned or shared). When configCode is provided, scopes to that single configuration. Supports filtering by direction, participant email/domain, include/exclude message IDs, and search. Pagination defaults: offset=0, limit=10, max limit=50.",
        "operationId": "ListMailboxMessages",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/MailboxMessageSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "configCode",
            "in": "query",
            "description": "Filter by configuration code (GUID, repeatable). Omit to search across all read-enabled configs.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"895c888f-c2ba-4c86-9d91-1eff95045e6a\" ]"
            }
          },
          {
            "name": "direction",
            "in": "query",
            "description": "Filter by email direction (Inbound = received emails, Outbound = sent emails)",
            "schema": {
              "enum": [
                "Inbound",
                "Outbound"
              ],
              "type": "string",
              "example": "Inbound"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search by subject or sender email/name",
            "schema": {
              "type": "string",
              "example": "invoice"
            }
          },
          {
            "name": "participantEmail",
            "in": "query",
            "description": "Filter by participant email address - matches From, To, and Cc fields. Can specify multiple (OR logic).",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"john@example.com\", \"jane@example.com\" ]"
            }
          },
          {
            "name": "participantDomain",
            "in": "query",
            "description": "Filter by participant email domain - matches From, To, and Cc fields. Can specify multiple (OR logic).",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"example.com\", \"acme.org\" ]"
            }
          },
          {
            "name": "includeMessageId",
            "in": "query",
            "description": "Force-include specific message UniqueIds regardless of participant filters (repeatable).",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"3b39ae56-f6f4-4e6c-82c9-661a5cc366ec\" ]"
            }
          },
          {
            "name": "excludeMessageId",
            "in": "query",
            "description": "Force-exclude specific message UniqueIds even if they match participant filters (repeatable).",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"3b39ae56-f6f4-4e6c-82c9-661a5cc366ec\" ]"
            }
          },
          {
            "name": "folderUniqueId",
            "in": "query",
            "description": "Filter to messages whose junction maps to any of these folder uniqueIds (repeatable, OR logic). Single-mailbox mode. Mutually exclusive with systemFolderType.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"3b39ae56-f6f4-4e6c-82c9-661a5cc366ec\" ]"
            }
          },
          {
            "name": "systemFolderType",
            "in": "query",
            "description": "Filter to messages in folders of the given system type (Inbox/Sent/Drafts/...). Combined-mailbox mode. Mutually exclusive with folderUniqueId.",
            "schema": {
              "enum": [
                "None",
                "Inbox",
                "Sent",
                "Drafts",
                "Junk",
                "Trash",
                "Archive",
                "Outbox",
                "GmailCategory",
                "GmailPromotionalCategory"
              ],
              "type": "string",
              "example": "Inbox"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExternalMailboxEmailSummaryDtoPagedResult"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/mailbox/send": {
      "post": {
        "tags": [
          "Email - Mailbox"
        ],
        "summary": "Send Email",
        "description": "Sends a composed email with automatic routing. If configCode is provided, sends via that mailbox — the user must own it or it must be send-shared, and it must be send-enabled. If omitted, uses the tenant's default mailbox. If no mailboxes are configured, sends via the platform default using the tenant's ReplyTo settings.",
        "operationId": "SendEmail",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "configCode",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendMailboxEmailRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/email-configs/{code}/conversations/{conversationId}": {
      "get": {
        "tags": [
          "Email - Mailbox"
        ],
        "summary": "Get Conversation",
        "description": "Returns all messages in a specific conversation thread, ordered by date, enriched with client associations based on participant email addresses matching client email rules. Each message includes summary fields (subject, sender, snippet, date) but not the full body - use the Get Message endpoint to retrieve the complete content. The configuration must have ReadEnabled set to true.",
        "operationId": "GetMailboxConversation",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          },
          {
            "name": "conversationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConversationWithAssociationsDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/email-configs/{code}/messages/{messageId}": {
      "get": {
        "tags": [
          "Email - Mailbox"
        ],
        "summary": "Get Message",
        "description": "Returns the full details of a specific message including HTML/plain-text body, recipients (to, cc), and attachment metadata. The body is fetched on-demand from the email provider, so this call may be slower than list endpoints. The configuration must have ReadEnabled set to true. If the response includes ReconnectRequired=true, the OAuth connection needs to be re-authorised before further requests will succeed.",
        "operationId": "GetMailboxMessage",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          },
          {
            "name": "messageId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExternalMailboxEmailDetailResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/email-configs/{code}/messages": {
      "post": {
        "tags": [
          "Email - Mailbox"
        ],
        "summary": "Send new email",
        "description": "Sends a new email from the tenant's connected mailbox. The configuration must have SendEnabled set to true. The sender (From) is determined by the email configuration. At least one To recipient and either HtmlBody or PlainTextBody is required. Attachments are supported via base64-encoded content.",
        "operationId": "SendMailboxMessage",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendMailboxEmailRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SendEmailResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "patch": {
        "tags": [
          "Email - Mailbox"
        ],
        "summary": "Mark messages as read or unread",
        "description": "Updates the read/unread status of one or more mailbox messages. The configuration must have ReadEnabled set to true. Provider sync (Microsoft Graph / Gmail) happens asynchronously — the response does not wait for the provider update.",
        "operationId": "PatchMailboxMessages",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchMailboxMessageRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/email-configs/{code}/messages/{messageId}/reply": {
      "post": {
        "tags": [
          "Email - Mailbox"
        ],
        "summary": "Reply to Message",
        "description": "Sends a reply to a specific mailbox message via the email provider. The configuration must have SendEnabled set to true. Set ReplyAll to true to reply to all original recipients, or provide explicit ToRecipients/CcRecipients to override. Supports attachments via the Attachments array. If the response includes ReconnectRequired=true, the OAuth connection needs to be re-authorised.",
        "operationId": "ReplyToMailboxMessage",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          },
          {
            "name": "messageId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "x-order": 400
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReplyEmailRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReplyEmailResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/email-configs/{code}/messages/{messageId}/attachments/{attachmentId}": {
      "get": {
        "tags": [
          "Email - Mailbox"
        ],
        "summary": "Get Attachment",
        "description": "Streams the raw content of a message attachment. Use for downloading files and resolving inline CID images in HTML email bodies. Returns the file with its original content type and caches for 1 hour.",
        "operationId": "GetMailboxMessageAttachment",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          },
          {
            "name": "attachmentId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "messageId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/email-configs/{code}/conversations/{conversationId}/tasks": {
      "post": {
        "tags": [
          "Email - Mailbox"
        ],
        "summary": "Link Task to Conversation",
        "description": "Creates an association between an email conversation and a task item.",
        "operationId": "LinkConversationTask",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          },
          {
            "name": "conversationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LinkConversationTaskRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CodeAndNameDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/email-configs/{code}/conversations/{conversationId}/tasks/{taskCode}": {
      "delete": {
        "tags": [
          "Email - Mailbox"
        ],
        "summary": "Unlink Task from Conversation",
        "description": "Removes the association between an email conversation and a task item.",
        "operationId": "UnlinkConversationTask",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          },
          {
            "name": "conversationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "taskCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/email-configs/{code}/sync": {
      "post": {
        "tags": [
          "Email - Mailbox"
        ],
        "summary": "Trigger Mailbox Sync",
        "description": "Queues an immediate sync for this mailbox configuration. Returns 202 Accepted — the sync happens asynchronously. New emails will appear after the sync completes (typically a few seconds).",
        "operationId": "TriggerMailboxSync",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "202": {
            "description": "Accepted"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/email-settings": {
      "get": {
        "tags": [
          "Email - Settings"
        ],
        "summary": "Get email settings",
        "description": "Returns the email settings for the specified tenant",
        "operationId": "GetEmailSettings",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailSettingsDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "put": {
        "tags": [
          "Email - Settings"
        ],
        "summary": "Update email settings",
        "description": "Updates the email settings for the specified tenant",
        "operationId": "UpdateEmailSettings",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateEmailSettingsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmailSettingsDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/engagements/accept/{guid}": {
      "get": {
        "tags": [
          "Engagement - Acceptance"
        ],
        "summary": "Get Engagement Details",
        "description": "Returns engagement information for the anonymous acceptance page.\n\nRequires a valid engagement GUID that has not yet been accepted or rejected.\nReturns tenant details, content blocks, and engagement summary.\n\n**Optional Query Parameters:**\n- callbackUrl: The URL to redirect the user back to after completing external steps (Direct Debit mandate setup, AML identity verification).\n  Used by both DD and AML providers as a return URL after their hosted flows complete.\n- preview: When true, skips updating LastViewed timestamp and Sent→Viewed status transition.\n  Used by practice staff to preview the acceptance page without affecting engagement tracking.",
        "operationId": "GetEngagementForAcceptance",
        "parameters": [
          {
            "name": "amlComplete",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "x-order": 400
          },
          {
            "name": "callbackUrl",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "guid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "x-order": 400
          },
          {
            "name": "preview",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EngagementAcceptanceDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/engagements/accept/{guid}/css": {
      "get": {
        "tags": [
          "Engagement - Acceptance"
        ],
        "summary": "Get Acceptance Page CSS",
        "description": "Returns the CSS for the design theme configured for this engagement.\n\nFalls back to tenant's default design theme if engagement settings don't specify one.",
        "operationId": "GetEngagementDesignThemeCss",
        "parameters": [
          {
            "name": "guid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "x-order": 400
          },
          {
            "name": "selector",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/css": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/engagements/accept/{guid}/pdf/proposal": {
      "get": {
        "tags": [
          "Engagement - Acceptance"
        ],
        "summary": "Get Proposal PDF",
        "description": "Downloads the proposal PDF document.\n\nRequires a valid engagement GUID that has not yet been accepted or rejected.",
        "operationId": "GetEngagementProposalPdfAnonymous",
        "parameters": [
          {
            "name": "disposition",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "guid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/engagements/accept/{guid}/pdf/letter-of-engagement": {
      "get": {
        "tags": [
          "Engagement - Acceptance"
        ],
        "summary": "Get Engagement Letter PDF",
        "description": "Downloads the letter of engagement PDF document.\n\nRequires a valid engagement GUID that has not yet been accepted or rejected.",
        "operationId": "GetEngagementLetterOfEngagementPdfAnonymous",
        "parameters": [
          {
            "name": "disposition",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "guid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/engagements/accept/{guid}/accept": {
      "post": {
        "tags": [
          "Engagement - Acceptance"
        ],
        "summary": "Accept Engagement",
        "description": "Accept Engagement by providing a signature.\n\nThe signature should be a base64-encoded image.\nIP address of the requester is automatically captured.",
        "operationId": "AcceptEngagement",
        "parameters": [
          {
            "name": "guid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "x-order": 400
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AcceptEngagementRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/practice/engagement-settings": {
      "get": {
        "tags": [
          "Engagement - Settings"
        ],
        "summary": "Get engagement settings",
        "description": "Returns the engagement settings for the specified tenant",
        "operationId": "GetEngagementSettings",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EngagementSettingsDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "put": {
        "tags": [
          "Engagement - Settings"
        ],
        "summary": "Update engagement settings",
        "description": "Updates the engagement settings for the specified tenant",
        "operationId": "UpdateEngagementSettings",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateEngagementSettingsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EngagementSettingsDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/engagements/{code}/pdf/{pdfType}/stream": {
      "get": {
        "tags": [
          "Engagements"
        ],
        "summary": "Stream Engagement PDF",
        "description": "Streams an engagement PDF. Requires a valid signed token. Used for mobile PDF viewing via Google Docs Viewer.",
        "operationId": "StreamEngagementPdf",
        "parameters": [
          {
            "name": "tenant",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          },
          {
            "name": "disposition",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "expires",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "x-order": 400
          },
          {
            "name": "pdfType",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Unauthorized"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/engagements": {
      "get": {
        "tags": [
          "Engagements"
        ],
        "summary": "List Engagements",
        "description": "Lists all Engagements for the given tenant.",
        "operationId": "ListEngagements",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/EngagementSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter by engagement status (Unsent, Sent, Accepted, Rejected)",
            "schema": {
              "enum": [
                "Unsent",
                "Sent",
                "Viewed",
                "Accepted",
                "Rejected"
              ],
              "type": "string",
              "example": "Sent"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search across engagement code, client name, and client code (minimum 3 characters)",
            "schema": {
              "type": "string",
              "example": "acme"
            }
          },
          {
            "name": "dateRange",
            "in": "query",
            "description": "Preset date range. If CustomDateRange, dateFrom and dateTo are required.",
            "schema": {
              "enum": [
                "ThisWeek",
                "NextWeek",
                "Last7Days",
                "Next7Days",
                "Last30Days",
                "Next30Days",
                "PreviousMonth",
                "ThisMonth",
                "NextMonth",
                "PreviousQuarter",
                "ThisQuarter",
                "NextQuarter",
                "PreviousYear",
                "ThisYear",
                "NextYear",
                "YearToDate",
                "PreviousFinancialYear",
                "ThisFinancialYear",
                "NextFinancialYear",
                "FinancialYearToDate",
                "Today",
                "CustomDateRange"
              ],
              "type": "string"
            }
          },
          {
            "name": "dateFrom",
            "in": "query",
            "description": "Filter engagements from this date. Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "dateTo",
            "in": "query",
            "description": "Filter engagements up to this date. Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EngagementDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Engagements"
        ],
        "summary": "Create Engagement",
        "description": "Creates a new Engagement for the specified tenant.",
        "operationId": "CreateEngagement",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateEngagementRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EngagementDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/engagements/{code}": {
      "get": {
        "tags": [
          "Engagements"
        ],
        "summary": "Get Engagement",
        "description": "Gets a Engagement for the specified tenant.",
        "operationId": "GetEngagement",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EngagementDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Engagements"
        ],
        "summary": "Update Engagement",
        "description": "Updates a Engagement for the specified tenant.",
        "operationId": "UpdateEngagement",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateEngagementRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EngagementDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Engagements"
        ],
        "summary": "Delete Engagement",
        "description": "Deletes a Engagement for the specified tenant.",
        "operationId": "DeleteEngagement",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/engagements/summary": {
      "get": {
        "tags": [
          "Engagements"
        ],
        "summary": "Get Engagement Summary",
        "description": "Returns a count and total annual value of engagements grouped by status for the tenant.\n\nOptionally filter by date range:\n- Use dateRange for preset ranges (ThisWeek, ThisMonth, ThisYear, etc.)\n- Use dateFrom/dateTo for custom ranges (when dateRange is CustomDateRange)\n- When using a preset range, dateFrom and dateTo must not be provided",
        "operationId": "GetEngagementSummary",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "dateFrom",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "x-order": 400
          },
          {
            "name": "dateRange",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/PresetDateRange"
            },
            "x-order": 400
          },
          {
            "name": "dateTo",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EngagementSummaryDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/engagements/{code}/email": {
      "post": {
        "tags": [
          "Engagements"
        ],
        "summary": "Email Engagement",
        "description": "Sends an email for the engagement using the tenant's email settings.\n\nThe email will be sent to the recipient specified in the engagement.\nThe email will be queued for sending and a message ID will be returned.\nA record will be created linking the engagement to the sent email.",
        "operationId": "SendEngagementEmail",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "get": {
        "tags": [
          "Engagements"
        ],
        "summary": "Get Engagement Emails",
        "description": "Gets all emails that have been sent for a specific engagement.\n\nReturns a list of emails with their message IDs and sent dates.\nThe list is ordered by most recent first.",
        "operationId": "GetEngagementEmails",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EngagementEmailDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/engagements/{code}/pdf/proposal": {
      "post": {
        "tags": [
          "Engagements"
        ],
        "summary": "Upload proposal PDF",
        "description": "Uploads a PDF document for the proposal.\n\nThe PDF should be sent as a base64-encoded string in the request body.\n\nRequest body example:\n{\n  \"pdfContent\": \"JVBERi0xLjQKJeLj...\"  // Base64-encoded PDF content\n}\n\nThe uploaded PDF will be stored in Azure Blob Storage and associated with this engagement.\nThe engagement's HasProposalPdf flag will be set to true upon successful upload.\n\nYou can retrieve this PDF later using the GET /{code}/pdf/proposal endpoint.\n\nNote: Uploading a new PDF will replace any existing proposal PDF for this engagement.",
        "operationId": "UploadEngagementProposalPdf",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UploadEngagementPdfRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "get": {
        "tags": [
          "Engagements"
        ],
        "summary": "Download proposal PDF",
        "description": "Downloads the proposal PDF document.\n\nReturns the PDF file as binary content with appropriate headers for download.\nThe response will include a Content-Disposition header with a filename in the format:\nproposal-{code}-{date}.pdf\n\nPrerequisites:\n- The engagement must exist\n- A PDF must have been previously uploaded (HasProposalPdf must be true)\n\nReturns:\n- 200: PDF file as application/pdf binary content\n- 404: If the engagement or PDF file is not found",
        "operationId": "GetEngagementProposalPdf",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          },
          {
            "name": "disposition",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/engagements/{code}/pdf/letter-of-engagement": {
      "post": {
        "tags": [
          "Engagements"
        ],
        "summary": "Upload letter of engagement PDF",
        "description": "Uploads a letter of engagement PDF document for the engagement.\n\nThe PDF should be sent as a base64-encoded string in the request body.\n\nRequest body example:\n{\n  \"pdfContent\": \"JVBERi0xLjQKJeLj...\"  // Base64-encoded PDF content\n}\n\nThe uploaded PDF will be stored in Azure Blob Storage and associated with this engagement.\nThe engagement's HasLofEPdf flag will be set to true upon successful upload.\n\nYou can retrieve this PDF later using the GET /{code}/pdf/letter-of-engagement endpoint.\n\nNote: Uploading a new PDF will replace any existing letter of engagement for this engagement.",
        "operationId": "UploadEngagementLetterOfEngagementPdf",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UploadEngagementPdfRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "get": {
        "tags": [
          "Engagements"
        ],
        "summary": "Download letter of engagement PDF",
        "description": "Downloads the letter of engagement PDF document.\n\nReturns the PDF file as binary content with appropriate headers for download.\nThe response will include a Content-Disposition header with a filename in the format:\nletter-of-engagement-{code}-{date}.pdf\n\nPrerequisites:\n- The engagement must exist\n- A letter of engagement PDF must have been previously uploaded (HasLofEPdf must be true)\n\nReturns:\n- 200: PDF file as application/pdf binary content\n- 404: If the engagement or letter of engagement PDF is not found",
        "operationId": "GetEngagementLetterOfEngagementPdf",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          },
          {
            "name": "disposition",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/external-proposals": {
      "get": {
        "tags": [
          "External Proposals"
        ],
        "summary": "List External Proposals",
        "description": "Lists proposals from the tenant's configured external proposal platform (e.g., Socket)",
        "operationId": "ListExternalProposals",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 200
          },
          {
            "name": "processing",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 0,
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 20,
              "example": "20"
            },
            "x-order": 501
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExternalProposalDtoPagedResult"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/external-proposals/{proposalId}": {
      "get": {
        "tags": [
          "External Proposals"
        ],
        "summary": "Get External Proposal",
        "description": "Gets a single proposal from the tenant's configured external proposal platform",
        "operationId": "GetExternalProposal",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "proposalId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExternalProposalDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/external-proposals/service-mapping": {
      "put": {
        "tags": [
          "External Proposals"
        ],
        "summary": "Map External Service",
        "description": "Maps an external service template to a Sodium BillableService. Creates or updates the mapping.",
        "operationId": "UpsertExternalServiceMapping",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpsertServiceMappingRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CodeAndNameDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/external-proposals/activate-services/{clientCode}": {
      "post": {
        "tags": [
          "External Proposals"
        ],
        "summary": "Activate Proposed Services",
        "description": "Activates all Proposed services for a client, setting them to Active status.",
        "operationId": "ActivateProposedServices",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "clientCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 213
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ActivateServicesResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/holidays": {
      "get": {
        "tags": [
          "Holidays"
        ],
        "summary": "List days",
        "description": "Lists all days for the given tenant.",
        "operationId": "Listdays",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/TenantHolidaySortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search term to filter results",
            "schema": {
              "type": "string",
              "example": "keyword"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantHolidayDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Holidays"
        ],
        "summary": "Create TenantHoliday",
        "description": "Creates a new TenantHoliday for the specified tenant.",
        "operationId": "CreateTenantHoliday",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTenantHolidayRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantHolidayDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/holidays/{code}": {
      "get": {
        "tags": [
          "Holidays"
        ],
        "summary": "Get TenantHoliday",
        "description": "Gets a TenantHoliday for the specified tenant.",
        "operationId": "GetTenantHoliday",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantHolidayDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Holidays"
        ],
        "summary": "Update TenantHoliday",
        "description": "Updates a TenantHoliday for the specified tenant.",
        "operationId": "UpdateTenantHoliday",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTenantHolidayRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantHolidayDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Holidays"
        ],
        "summary": "Delete TenantHoliday",
        "description": "Deletes a TenantHoliday for the specified tenant.",
        "operationId": "DeleteTenantHoliday",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/import-jobs/{code}": {
      "get": {
        "tags": [
          "Import Jobs"
        ],
        "summary": "Get Import Job Status",
        "description": "Returns the current status of an import job",
        "operationId": "GetImportJob",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImportJobDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/import-jobs": {
      "get": {
        "tags": [
          "Import Jobs"
        ],
        "summary": "List Import Jobs",
        "description": "Returns a paginated list of import jobs for the tenant",
        "operationId": "ListImportJobs",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          }
        }
      }
    },
    "/mailinglist/subscribe": {
      "post": {
        "tags": [
          "Marketing"
        ],
        "summary": "Subscribe to Mailing List",
        "operationId": "SubscribeToMailingList",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MailingListSubscriptionDto"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IResult"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IResult"
                }
              }
            }
          }
        }
      }
    },
    "/tenants/{tenant}/media-library/images": {
      "get": {
        "tags": [
          "Media Library"
        ],
        "summary": "List ImageAssets",
        "description": "Lists all ImageAssets for the given tenant.",
        "operationId": "ListImageAssets",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/ImageAssetSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search term to filter results",
            "schema": {
              "type": "string",
              "example": "keyword"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImageAssetDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Media Library"
        ],
        "summary": "Create ImageAsset",
        "operationId": "CreateImageAsset",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "required": [
                  "file",
                  "name"
                ],
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "description": {
                    "type": "string"
                  },
                  "file": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              },
              "encoding": {
                "name": {
                  "style": "form"
                },
                "description": {
                  "style": "form"
                },
                "file": {
                  "style": "form"
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImageAssetDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/media-library/images/{code}": {
      "get": {
        "tags": [
          "Media Library"
        ],
        "summary": "Get ImageAsset",
        "description": "Gets a ImageAsset for the specified tenant.",
        "operationId": "GetImageAsset",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImageAssetDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Media Library"
        ],
        "summary": "Update ImageAsset",
        "description": "Updates a ImageAsset for the specified tenant.",
        "operationId": "UpdateImageAsset",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateImageAssetRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ImageAssetDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Media Library"
        ],
        "summary": "Delete ImageAsset",
        "description": "Deletes a ImageAsset for the specified tenant.",
        "operationId": "DeleteImageAsset",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/media-library/images/{code}/content": {
      "get": {
        "tags": [
          "Media Library"
        ],
        "summary": "Streams image content",
        "operationId": "StreamImageContent",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "304": {
            "description": "Not Modified"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/metadata/accounting-connection-types": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "AccountingConnectionType",
        "description": "Retrieves metadata (such as the display name) for the AccountingConnectionType enum.",
        "operationId": "GetAccountingConnectionType",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/agent-authorisation-statuses": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "AgentAuthorisationStatus",
        "description": "Retrieves metadata (such as the display name) for the AgentAuthorisationStatus enum.",
        "operationId": "GetAgentAuthorisationStatus",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/agent-authorisation-types": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "AgentAuthorisationType",
        "description": "Retrieves metadata (such as the display name) for the AgentAuthorisationType enum.",
        "operationId": "GetAgentAuthorisationType",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/aml-contact-statuses": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "AmlContactStatus",
        "description": "Retrieves metadata for the AmlContactStatus enum (onboarding/AML check status per contact).",
        "operationId": "GetAmlContactStatus",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/aml-risk-assessment-statuses": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "AmlRiskAssessmentStatus",
        "description": "Retrieves metadata (such as the display name and colors) for the AmlRiskAssessmentStatus enum.",
        "operationId": "GetAmlRiskAssessmentStatus",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/aml-risk-levels": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "AmlRiskLevel",
        "description": "Retrieves metadata (such as the display name and colors) for the AmlRiskLevel enum.",
        "operationId": "GetAmlRiskLevel",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/aml-statuses": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "AmlStatus",
        "description": "Retrieves metadata (such as the display name and colors) for the AmlStatus enum.",
        "operationId": "GetAmlStatus",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/ai-activities": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "AiActivity",
        "description": "Retrieves metadata (such as the display name) for the AiActivity enum.",
        "operationId": "GetAiActivity",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/ai-contexts": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "AiContext",
        "description": "Retrieves metadata (such as the display name) for the AiContext enum.",
        "operationId": "GetAiContext",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/assignment-types": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "AssignmentType",
        "description": "Retrieves metadata (such as the display name) for the AssignmentType enum.",
        "operationId": "GetAssignmentType",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/authentication-types": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "AuthenticationType",
        "description": "Retrieves metadata (such as the display name) for the AuthenticationType enum.",
        "operationId": "GetAuthenticationType",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/billing-frequencies": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "BillingFrequency",
        "description": "Retrieves metadata (such as the display name) for the BillingFrequency enum.",
        "operationId": "GetBillingFrequency",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/client-billing-line-item-statuses": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "ClientBillingLineItemStatus",
        "description": "Retrieves metadata (such as the display name and colors) for the ClientBillingLineItemStatus enum.",
        "operationId": "GetClientBillingLineItemStatus",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/client-invoice-submission-statuses": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "ClientInvoiceSubmissionStatus",
        "description": "Retrieves metadata (such as the display name and colors) for the ClientInvoiceSubmissionStatus enum.",
        "operationId": "GetClientInvoiceSubmissionStatus",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/client-association-types": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "ClientAssociationType",
        "description": "Retrieves metadata (such as the display name) for the ClientAssociationType enum.",
        "operationId": "GetClientAssociationType",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/client-contact-types": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "ClientContactType",
        "description": "Retrieves metadata (such as the display name) for the ClientContactType enum.",
        "operationId": "GetClientContactType",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/client-date-source-types": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "ClientDateSourceType",
        "description": "Retrieves metadata for the ClientDateSourceType enum, indicating whether a recurring task uses a built-in key date or a tenant-defined custom field date.",
        "operationId": "GetClientDateSourceType",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/client-date-types": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "ClientDateType",
        "description": "Retrieves metadata (such as the display name) for the ClientDateType enum.",
        "operationId": "GetClientDateType",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/client-csv-target-fields": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "ClientCsvTargetField",
        "description": "Retrieves metadata (such as the display name) for the ClientCsvTargetField enum.",
        "operationId": "GetClientCsvTargetField",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/csv-import-match-fields": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "CsvImportMatchField",
        "description": "Retrieves metadata (such as the display name) for the CsvImportMatchField enum.",
        "operationId": "GetCsvImportMatchField",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/client-statuses": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "ClientStatus",
        "description": "Retrieves metadata (such as the display name and colors) for the ClientStatus enum.",
        "operationId": "GetClientStatus",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/client-types": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "ClientType",
        "description": "Retrieves metadata (such as the display name) for the ClientType enum.",
        "operationId": "GetClientType",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/company-status": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "CompanyStatus",
        "description": "Retrieves metadata (such as the display name) for the CompanyStatus enum.",
        "operationId": "GetCompanyStatus",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/connection-statuses": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "ConnectionStatus",
        "description": "Retrieves metadata (such as the display name) for the ConnectionStatus enum.",
        "operationId": "GetConnectionStatus",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/content-block-categories": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "ContentBlockCategory",
        "description": "Retrieves metadata (such as the display name) for the ContentBlockCategory enum.",
        "operationId": "GetContentBlockCategory",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/custom-field-data-types": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "CustomFieldDataType",
        "description": "Retrieves metadata for the CustomFieldDataType enum, including display names for each custom field data type.",
        "operationId": "GetCustomFieldDataType",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/custom-field-entity-types": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "CustomFieldEntityType",
        "description": "Retrieves metadata for the CustomFieldEntityType enum, including display names for each entity type that supports custom fields.",
        "operationId": "GetCustomFieldEntityType",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/boolean-display-modes": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "BooleanDisplayMode",
        "description": "Retrieves metadata for the BooleanDisplayMode enum, including display mode options for Boolean fields.",
        "operationId": "GetBooleanDisplayMode",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/field-display-widths": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "FieldDisplayWidth",
        "description": "Retrieves metadata for the FieldDisplayWidth enum, including preset width options for custom field and data form inputs.",
        "operationId": "GetFieldDisplayWidth",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/background-image-positions": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "BackgroundImagePosition",
        "description": "Controls the positioning of a background image on PDF pages.",
        "operationId": "GetBackgroundImagePosition",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/page-selections": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "PageSelection",
        "description": "Controls which pages a feature applies to in PDF documents.",
        "operationId": "GetPageSelection",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/template-types": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "TemplateType",
        "description": "Retrieves metadata (such as the display name) for the TemplateType enum.",
        "operationId": "GetTemplateType",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/theme-fonts": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "ThemeFont",
        "description": "Retrieves metadata for the ThemeFont enum, including font family, fallback, and Google Font URL.",
        "operationId": "GetThemeFont",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/days-before-or-after": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "DaysBeforeOrAfter",
        "description": "Retrieves metadata (such as the display name) for the DaysBeforeOrAfter enum.",
        "operationId": "GetDaysBeforeOrAfter",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/data-form-answer-review-statuses": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "DataFormAnswerReviewStatus",
        "description": "Retrieves metadata (such as the display name and colors) for the DataFormAnswerReviewStatus enum.",
        "operationId": "GetDataFormAnswerReviewStatus",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/data-form-request-statuses": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "DataFormRequestStatus",
        "description": "Retrieves metadata (such as the display name and colors) for the DataFormRequestStatus enum.",
        "operationId": "GetDataFormRequestStatus",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/data-form-statuses": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "DataFormStatus",
        "description": "Retrieves metadata (such as the display name and colors) for the DataFormStatus enum.",
        "operationId": "GetDataFormStatus",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/document-request-statuses": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "DocumentRequestStatus",
        "description": "Retrieves metadata (such as the display name and colors) for the DocumentRequestStatus enum.",
        "operationId": "GetDocumentRequestStatus",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/due-date-types": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "DueDateType",
        "description": "How a recurring task's projected DueDate is calculated: offset from start, fixed annual date, or anchored to a client date.",
        "operationId": "GetDueDateType",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/email-broadcast-statuses": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "EmailBroadcastStatus",
        "description": "Retrieves metadata (such as the display name and colors) for the EmailBroadcastStatus enum.",
        "operationId": "GetEmailBroadcastStatus",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/email-broadcast-recipient-statuses": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "EmailBroadcastRecipientStatus",
        "description": "Retrieves metadata (such as the display name and colors) for the EmailBroadcastRecipientStatus enum.",
        "operationId": "GetEmailBroadcastRecipientStatus",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/filing-history-categories": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "FilingHistoryCategory",
        "description": "Retrieves metadata (such as the display name) for the FilingHistoryCategory enum.",
        "operationId": "GetFilingHistoryCategory",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/holiday-adjustments": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "HolidayAdjustment",
        "description": "Retrieves metadata (such as the display name) for the HolidayAdjustment enum.",
        "operationId": "GetHolidayAdjustment",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/invoice-statuses": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "InvoiceStatus",
        "description": "Retrieves metadata (such as the display name) for the InvoiceStatus enum.",
        "operationId": "GetInvoiceStatus",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/kpi-periods": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "KpiPeriod",
        "description": "Retrieves metadata (such as the display name) for the KpiPeriod enum.",
        "operationId": "GetKpiPeriod",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/link-types": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "LinkType",
        "description": "Retrieves metadata (such as the display name and icon) for the LinkType enum.",
        "operationId": "GetLinkType",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/marital-statuses": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "MaritalStatus",
        "description": "Retrieves metadata (such as the display name) for the MaritalStatus enum.",
        "operationId": "GetMaritalStatus",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/month-day-types": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "MonthDayType",
        "description": "Retrieves metadata (such as the display name) for the MonthDayType enum.",
        "operationId": "GetMonthDayType",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/nationalities": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "Nationality",
        "description": "Retrieves metadata (such as the display name) for the Nationality enum.",
        "operationId": "GetNationality",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/permissions": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "Permission",
        "description": "Retrieves metadata for the Permission enum, including display names and descriptions of each permission level.",
        "operationId": "GetPermission",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/permissible-entities": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "PermissibleEntity",
        "description": "Retrieves metadata for the PermissibleEntity enum, including display names of entities that can have permissions applied to them.",
        "operationId": "GetPermissibleEntity",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/platform-capabilities": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "PlatformCapability",
        "description": "Retrieves metadata for the PlatformCapability enum, including display names of capabilities that third-party platforms can provide.",
        "operationId": "GetPlatformCapability",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/preset-date-ranges": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "PresetDateRange",
        "description": "Retrieves metadata for the PresetDateRange enum, including display names for preset date range options.",
        "operationId": "GetPresetDateRange",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/professional-bodies": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "ProfessionalBody",
        "description": "Retrieves metadata (such as the display name) for the ProfessionalBody enum.",
        "operationId": "GetProfessionalBody",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/engagement-statuses": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "EngagementStatus",
        "description": "Retrieves metadata (such as the display name) for the EngagementStatus enum.",
        "operationId": "GetEngagementStatus",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/engagement-types": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "EngagementType",
        "description": "Retrieves metadata (such as the display name) for the EngagementType enum.",
        "operationId": "GetEngagementType",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/recurrence-units": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "RecurrenceUnit",
        "description": "Retrieves metadata (such as the display name) for the RecurrenceUnit enum.",
        "operationId": "GetRecurrenceUnit",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/role-types": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "RoleType",
        "description": "Retrieves metadata (such as the display name) for the RoleType enum.",
        "operationId": "GetRoleType",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/service-categories": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "ServiceCategory",
        "description": "Retrieves metadata (such as the display name) for the ServiceCategory enum.",
        "operationId": "GetServiceCategory",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/service-pricing-modes": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "ServicePricingMode",
        "description": "Retrieves metadata for the ServicePricingMode enum, indicating whether a service uses Revenue Range or Custom Tiers pricing.",
        "operationId": "GetServicePricingMode",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/service-statuses": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "ServiceStatus",
        "description": "Retrieves metadata (such as the display name, icon, and colors) for the ServiceStatus enum.",
        "operationId": "GetServiceStatus",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/sic-codes": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "SicCode",
        "description": "Retrieves metadata (such as the code and description) for the SicCode enum.",
        "operationId": "GetSicCode",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/statutory-date-types": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "StatutoryDateType",
        "description": "How a recurring task's projected StatutoryDueDate is calculated: none, fixed annual date, or anchored to a client date.",
        "operationId": "GetStatutoryDateType",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/system-roles": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "SystemRole",
        "description": "Retrieves metadata (such as the display name) for the SystemRole enum.",
        "operationId": "GetSystemRole",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/task-item-statuses": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "TaskItemStatus",
        "description": "Retrieves metadata (such as the display name, icon, and colors) for the TaskItemStatus enum.",
        "operationId": "GetTaskItemStatus",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/tenant-statuses": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "TenantStatus",
        "description": "Retrieves metadata (such as the display name and colors) for the TenantStatus enum.",
        "operationId": "GetTenantStatus",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/time-billing-line-modes": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "TimeBillingLineMode",
        "description": "Retrieves metadata (such as the display name and description) for the TimeBillingLineMode enum — how billed time entries are shaped into billing line items.",
        "operationId": "GetTimeBillingLineMode",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/time-entry-billing-states": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "TimeEntryBillingState",
        "description": "Retrieves metadata (such as the display name and colors) for the TimeEntryBillingState enum.",
        "operationId": "GetTimeEntryBillingState",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/tenant-user-statuses": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "TenantUserStatus",
        "description": "Retrieves metadata (such as the display name and colors) for the TenantUserStatus enum.",
        "operationId": "GetTenantUserStatus",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/task-start-types": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "StartDateType",
        "description": "Retrieves metadata (such as the display name) for the StartDateType enum.",
        "operationId": "GetStartDateType",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/task-date-bases": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "TaskDateBasis",
        "description": "Which date is the user-set driving date on a recurring task (StartDate or DueDate). Also used as a filter discriminator on task list queries.",
        "operationId": "GetTaskDateBasis",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/user-activity-types": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "UserActivityType",
        "description": "Retrieves metadata (such as the display name) for the UserActivityType enum.",
        "operationId": "GetUserActivityType",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/vat-rates": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "VatRate",
        "description": "Retrieves metadata (such as the display name) for the VatRate enum.",
        "operationId": "GetVatRate",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/vat-reporting-periods": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "VatReportingPeriod",
        "description": "Retrieves metadata (such as the display name) for the VatReportingPeriod enum.",
        "operationId": "GetVatReportingPeriod",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/vat-schemes": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "VatScheme",
        "description": "Retrieves metadata (such as the display name) for the VatScheme enum.",
        "operationId": "GetVatScheme",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/smart-name-tokens": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "SmartNameToken",
        "description": "Retrieves the available tokens for smart name templates. Use {{ TokenName }} syntax in TaskNameTemplate or OutputNameTemplate (e.g. \"VAT Return - {{ ClientName }} - {{ Quarter }} {{ Year }}\"). Date tokens resolve from the context date. ClientName, ClientCode, and ClientInternalRef resolve from the associated client.",
        "operationId": "GetSmartNameToken",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/week-day-types": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "WeekDayType",
        "description": "Retrieves metadata (such as the display name) for the WeekDayType enum.",
        "operationId": "GetWeekDayType",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/workflow-step-assignment-types": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "WorkflowStepAssignmentType",
        "description": "Retrieves metadata (such as the display name) for the WorkflowStepAssignmentType enum.",
        "operationId": "GetWorkflowStepAssignmentType",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/workflow-step-types": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "WorkflowStepType",
        "description": "Retrieves metadata (such as the display name) for the WorkflowStepType enum.",
        "operationId": "GetWorkflowStepType",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/EnumMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/metadata/third-party-platforms": {
      "get": {
        "tags": [
          "Metadata"
        ],
        "summary": "ThirdPartyPlatforms",
        "description": "Retrieves metadata about available third-party platforms and their capabilities.",
        "operationId": "GetThirdPartyPlatforms",
        "parameters": [
          {
            "name": "tenant",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ThirdPartyPlatformMetadata"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/packages": {
      "get": {
        "tags": [
          "Packages"
        ],
        "summary": "List Packages",
        "description": "Lists all packages.",
        "operationId": "GetPackages",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PackageDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/packages/{code}": {
      "get": {
        "tags": [
          "Packages"
        ],
        "summary": "Get Package",
        "description": "Gets a specific package by its code.",
        "operationId": "GetPackage",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PackageDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/packages/{code}/pricing": {
      "get": {
        "tags": [
          "Packages"
        ],
        "summary": "List Pricing Tiers for Package",
        "description": "Lists all available pricing tiers for a specific package.",
        "operationId": "GetPackagePricingTiers",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PricingTierDto"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/HttpValidationProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/pricing/tiers/{packageCode}/{clientCount}": {
      "get": {
        "tags": [
          "Packages"
        ],
        "summary": "Get Pricing Tier",
        "description": "Returns the applicable pricing tier for a given package and client count. Anonymous endpoint for public pricing pages.",
        "operationId": "GetPricingTierForClientCount",
        "parameters": [
          {
            "name": "clientCount",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "x-order": 400
          },
          {
            "name": "packageCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PricingTierDto"
                }
              }
            }
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/pending-workflow-steps": {
      "get": {
        "tags": [
          "Pending Workflow Steps"
        ],
        "summary": "List Pending Workflow Steps",
        "description": "Returns a paged list of manual-mode outbound workflow steps that are ready to send. These are steps where dependencies are met and a user needs to review and trigger the send.",
        "operationId": "ListPendingWorkflowSteps",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/PendingWorkflowStepSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "stepType",
            "in": "query",
            "description": "Filter by step type (SendEmail, DocumentRequest, DocumentApproval, ClientConfirmation, SendDataForm)",
            "schema": {
              "enum": [
                "Standard",
                "SendEmail",
                "DocumentRequest",
                "DocumentApproval",
                "ClientConfirmation",
                "SendDataForm",
                "SetServiceStage",
                "UpdateClientData",
                "SetPipelineStage"
              ],
              "type": "string",
              "example": "SendEmail"
            }
          },
          {
            "name": "assignedUserCode",
            "in": "query",
            "description": "Filter by the user assigned to the step",
            "schema": {
              "type": "string",
              "example": "USR001"
            }
          },
          {
            "name": "assignedTeamCode",
            "in": "query",
            "description": "Filter by the team assigned to the step",
            "schema": {
              "type": "string",
              "example": "TEAM001"
            }
          },
          {
            "name": "isUnassigned",
            "in": "query",
            "description": "When true, returns only steps with no assigned user. Combines with assignedUserCode as OR.",
            "schema": {
              "type": "boolean",
              "example": "true"
            }
          },
          {
            "name": "clientCode",
            "in": "query",
            "description": "Filter by client code",
            "schema": {
              "type": "string",
              "example": "acme-ltd"
            }
          },
          {
            "name": "managerCode",
            "in": "query",
            "description": "Filter by client manager user code",
            "schema": {
              "type": "string",
              "example": "USR001"
            }
          },
          {
            "name": "partnerCode",
            "in": "query",
            "description": "Filter by client partner user code",
            "schema": {
              "type": "string",
              "example": "USR002"
            }
          },
          {
            "name": "taskCategoryCode",
            "in": "query",
            "description": "Filter by task category code",
            "schema": {
              "type": "string",
              "example": "CAT001"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search across step name, task title, and client name (minimum 3 characters)",
            "schema": {
              "type": "string",
              "example": "tax return"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PendingWorkflowStepDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "patch": {
        "tags": [
          "Pending Workflow Steps"
        ],
        "summary": "Bulk Update Workflow Steps",
        "description": "Updates multiple workflow steps at once. Supports skipping steps and reassigning to a user.",
        "operationId": "BulkUpdatePendingWorkflowSteps",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkUpdateWorkflowStepsRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkUpdateResult"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/pipeline-onboarding-task-templates": {
      "get": {
        "tags": [
          "Pipeline - Intake Tasks"
        ],
        "summary": "List PipelineOnboardingTaskTemplates",
        "description": "Lists all PipelineOnboardingTaskTemplates for the given tenant.",
        "operationId": "ListPipelineOnboardingTaskTemplates",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/PipelineOnboardingTaskTemplateSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "pipelineCode",
            "in": "query",
            "description": "Filter by pipeline code",
            "schema": {
              "type": "string",
              "example": "sales-pipeline"
            }
          },
          {
            "name": "isActive",
            "in": "query",
            "description": "Filter by active status (true = active only, false = inactive only)",
            "schema": {
              "type": "boolean",
              "example": "true"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search across template code, name, and description (minimum 3 characters)",
            "schema": {
              "type": "string",
              "example": "qualify"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PipelineOnboardingTaskTemplateDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Pipeline - Intake Tasks"
        ],
        "summary": "Create PipelineOnboardingTaskTemplate",
        "description": "Creates a new PipelineOnboardingTaskTemplate for the specified tenant.",
        "operationId": "CreatePipelineOnboardingTaskTemplate",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePipelineOnboardingTaskTemplateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PipelineOnboardingTaskTemplateDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/pipeline-onboarding-task-templates/{code}": {
      "get": {
        "tags": [
          "Pipeline - Intake Tasks"
        ],
        "summary": "Get PipelineOnboardingTaskTemplate",
        "description": "Gets a PipelineOnboardingTaskTemplate for the specified tenant.",
        "operationId": "GetPipelineOnboardingTaskTemplate",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PipelineOnboardingTaskTemplateDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Pipeline - Intake Tasks"
        ],
        "summary": "Update PipelineOnboardingTaskTemplate",
        "description": "Updates a PipelineOnboardingTaskTemplate for the specified tenant.",
        "operationId": "UpdatePipelineOnboardingTaskTemplate",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdatePipelineOnboardingTaskTemplateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PipelineOnboardingTaskTemplateDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Pipeline - Intake Tasks"
        ],
        "summary": "Delete PipelineOnboardingTaskTemplate",
        "description": "Deletes a PipelineOnboardingTaskTemplate for the specified tenant.",
        "operationId": "DeletePipelineOnboardingTaskTemplate",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/pipeline-onboarding-task-templates/{code}/library-version": {
      "put": {
        "tags": [
          "Pipeline - Intake Tasks"
        ],
        "summary": "Revert PipelineOnboardingTaskTemplate to Library",
        "description": "Reverts the PipelineOnboardingTaskTemplate to the current library template version, overwriting any local edits. The PipelineOnboardingTaskTemplate's code is preserved so it remains addressable at the same URL. Returns 400 if the PipelineOnboardingTaskTemplate was not imported from the library, or 404 if the PipelineOnboardingTaskTemplate or its source library template no longer exists.",
        "operationId": "RevertPipelineOnboardingTaskTemplateToLibraryVersion",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PipelineOnboardingTaskTemplateDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/pipelines": {
      "get": {
        "tags": [
          "Pipelines"
        ],
        "summary": "List Pipelines",
        "description": "Lists all Pipelines for the given tenant.",
        "operationId": "ListPipelines",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/PipelineSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "isArchived",
            "in": "query",
            "description": "Filter by archived status (true = archived only, false = active only)",
            "schema": {
              "type": "boolean",
              "example": "false"
            }
          },
          {
            "name": "hasStages",
            "in": "query",
            "description": "Filter to only pipelines that have stages defined (true = with stages only)",
            "schema": {
              "type": "boolean",
              "example": "true"
            }
          },
          {
            "name": "showKanbanBoard",
            "in": "query",
            "description": "Filter to only pipelines with kanban board enabled (true = kanban-enabled only)",
            "schema": {
              "type": "boolean",
              "example": "true"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search across pipeline code and name (minimum 3 characters)",
            "schema": {
              "type": "string",
              "example": "sales"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PipelineDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Pipelines"
        ],
        "summary": "Create Pipeline",
        "description": "Creates a new Pipeline for the specified tenant.",
        "operationId": "CreatePipeline",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePipelineRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PipelineDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/pipelines/{code}": {
      "get": {
        "tags": [
          "Pipelines"
        ],
        "summary": "Get Pipeline",
        "description": "Gets a Pipeline for the specified tenant.",
        "operationId": "GetPipeline",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PipelineDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Pipelines"
        ],
        "summary": "Update Pipeline",
        "description": "Updates a Pipeline for the specified tenant.",
        "operationId": "UpdatePipeline",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdatePipelineRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PipelineDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Pipelines"
        ],
        "summary": "Delete Pipeline",
        "description": "Deletes a Pipeline for the specified tenant.",
        "operationId": "DeletePipeline",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/pipelines/library": {
      "get": {
        "tags": [
          "Pipelines"
        ],
        "summary": "List Library Pipelines",
        "description": "List all Pipelines available in the library as templates. Use optional 'search' query parameter to filter by Code, Name, or Description.",
        "operationId": "ListLibraryPipelines",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 150
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PipelineDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/pipelines/library/{code}": {
      "get": {
        "tags": [
          "Pipelines"
        ],
        "summary": "Get Library Pipeline",
        "description": "Get details of a specific Pipeline template from the library",
        "operationId": "GetLibraryPipeline",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PipelineDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/pipelines/{code}/library-version": {
      "put": {
        "tags": [
          "Pipelines"
        ],
        "summary": "Revert Pipeline to Library",
        "description": "Reverts the Pipeline to the current library template version, overwriting any local edits. The Pipeline's code is preserved so it remains addressable at the same URL. Returns 400 if the Pipeline was not imported from the library, or 404 if the Pipeline or its source library template no longer exists.",
        "operationId": "RevertPipelineToLibraryVersion",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PipelineDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/pipelines/library/import": {
      "post": {
        "tags": [
          "Pipelines"
        ],
        "summary": "Import Pipelines from Library",
        "description": "Imports one or more pipelines from the library, cascading their stages, intake task templates, recurring tasks and referenced workflows into the tenant.",
        "operationId": "ImportPipelinesFromLibrary",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImportPipelinesFromLibraryRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PipelineDto"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/practice": {
      "get": {
        "tags": [
          "Practice"
        ],
        "summary": "Get Practice Details",
        "description": "Returns the practice details for the specified tenant",
        "operationId": "GetPracticeDetails",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PracticeDetailsDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "put": {
        "tags": [
          "Practice"
        ],
        "summary": "Update Practice Details",
        "description": "Updates the practice details for the specified tenant",
        "operationId": "UpdatePracticeDetails",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdatePracticeDetailsRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PracticeDetailsDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/professionalclearance/items": {
      "get": {
        "tags": [
          "Professional Clearance"
        ],
        "summary": "List ProfessionalClearanceRequestItems",
        "description": "Lists all ProfessionalClearanceRequestItems for the given tenant.",
        "operationId": "ListProfessionalClearanceRequestItems",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/ProfessionalClearanceRequestItemSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search term to filter results",
            "schema": {
              "type": "string",
              "example": "keyword"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProfessionalClearanceRequestItemDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Professional Clearance"
        ],
        "summary": "Create ProfessionalClearanceRequestItem",
        "description": "Creates a new ProfessionalClearanceRequestItem for the specified tenant.",
        "operationId": "CreateProfessionalClearanceRequestItem",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateProfessionalClearanceRequestItemRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProfessionalClearanceRequestItemDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/professionalclearance/items/{code}": {
      "get": {
        "tags": [
          "Professional Clearance"
        ],
        "summary": "Get ProfessionalClearanceRequestItem",
        "description": "Gets a ProfessionalClearanceRequestItem for the specified tenant.",
        "operationId": "GetProfessionalClearanceRequestItem",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProfessionalClearanceRequestItemDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Professional Clearance"
        ],
        "summary": "Update ProfessionalClearanceRequestItem",
        "description": "Updates a ProfessionalClearanceRequestItem for the specified tenant.",
        "operationId": "UpdateProfessionalClearanceRequestItem",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateProfessionalClearanceRequestItemRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProfessionalClearanceRequestItemDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Professional Clearance"
        ],
        "summary": "Delete ProfessionalClearanceRequestItem",
        "description": "Deletes a ProfessionalClearanceRequestItem for the specified tenant.",
        "operationId": "DeleteProfessionalClearanceRequestItem",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/professionalclearance/settings": {
      "get": {
        "tags": [
          "Professional Clearance"
        ],
        "summary": "Get Settings",
        "description": "Returns the professional clearance letter settings for the specified tenant",
        "operationId": "GetProfessionalClearanceLetterSettings",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProfessionalClearanceLetterSettingsDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "put": {
        "tags": [
          "Professional Clearance"
        ],
        "summary": "Update Settings",
        "description": "Updates the professional clearance letter settings for the specified tenant",
        "operationId": "UpdateProfessionalClearanceLetterSettings",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateProfessionalClearanceLetterSettingsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProfessionalClearanceLetterSettingsDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{clientCode}/pcl/items": {
      "get": {
        "tags": [
          "Professional Clearance"
        ],
        "summary": "Get Client Clearance Items",
        "description": "Returns all professional clearance request items for the client based on their non-inactive billable services, including global items",
        "operationId": "GetClientPclItems",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "clientCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 213
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ProfessionalClearanceRequestItemDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/reports/service-delivery": {
      "get": {
        "tags": [
          "Reports"
        ],
        "summary": "Get Service Delivery Report",
        "description": "Service Delivery Turnaround: headline KPIs (avg/median turnaround, on-time rate, statutory compliance, currently overdue) plus a breakdown table grouped by service, client, assignee, or completion month. The cohort is tasks completed in the requested window; Skipped tasks are excluded unless includeSkipped=true.",
        "operationId": "GetServiceDeliveryReport",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "dateRange",
            "in": "query",
            "description": "Preset date range for the completion window (default Last30Days). If CustomDateRange, startDate and endDate are required.",
            "schema": {
              "enum": [
                "ThisWeek",
                "NextWeek",
                "Last7Days",
                "Next7Days",
                "Last30Days",
                "Next30Days",
                "PreviousMonth",
                "ThisMonth",
                "NextMonth",
                "PreviousQuarter",
                "ThisQuarter",
                "NextQuarter",
                "PreviousYear",
                "ThisYear",
                "NextYear",
                "YearToDate",
                "PreviousFinancialYear",
                "ThisFinancialYear",
                "NextFinancialYear",
                "FinancialYearToDate",
                "Today",
                "CustomDateRange"
              ],
              "type": "string"
            }
          },
          {
            "name": "startDate",
            "in": "query",
            "description": "Completion window start (inclusive). Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "description": "Completion window end (inclusive). Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "groupBy",
            "in": "query",
            "description": "Breakdown dimension: Service (default), Client, AssignedUser, or Month",
            "schema": {
              "enum": [
                "Service",
                "Client",
                "AssignedUser",
                "Month"
              ],
              "type": "string"
            }
          },
          {
            "name": "includeSkipped",
            "in": "query",
            "description": "Count Skipped tasks as delivered alongside Completed ones (default false)",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "service",
            "in": "query",
            "description": "Filter by billable service code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"SRV-001\" ]"
            }
          },
          {
            "name": "client",
            "in": "query",
            "description": "Filter by client code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"CLI-001\" ]"
            }
          },
          {
            "name": "user",
            "in": "query",
            "description": "Filter by assigned user code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"USR-001\" ]"
            }
          },
          {
            "name": "team",
            "in": "query",
            "description": "Filter by assigned team code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"payroll-team\" ]"
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "Filter by task category code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"CAT-001\" ]"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceDeliveryReportDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/reports/service-delivery/steps": {
      "get": {
        "tags": [
          "Reports"
        ],
        "summary": "Get Service Delivery Step Bottlenecks",
        "description": "Step-level drill-down for one billable service: average elapsed time per workflow step (from the previous step's completion, so idle time counts), chase counts, and the client-wait vs internal split - is it us or the client.",
        "operationId": "GetServiceDeliveryStepBottlenecks",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "serviceCode",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "dateRange",
            "in": "query",
            "description": "Preset date range for the completion window (default Last30Days). If CustomDateRange, startDate and endDate are required.",
            "schema": {
              "enum": [
                "ThisWeek",
                "NextWeek",
                "Last7Days",
                "Next7Days",
                "Last30Days",
                "Next30Days",
                "PreviousMonth",
                "ThisMonth",
                "NextMonth",
                "PreviousQuarter",
                "ThisQuarter",
                "NextQuarter",
                "PreviousYear",
                "ThisYear",
                "NextYear",
                "YearToDate",
                "PreviousFinancialYear",
                "ThisFinancialYear",
                "NextFinancialYear",
                "FinancialYearToDate",
                "Today",
                "CustomDateRange"
              ],
              "type": "string"
            }
          },
          {
            "name": "startDate",
            "in": "query",
            "description": "Completion window start (inclusive). Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "description": "Completion window end (inclusive). Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "groupBy",
            "in": "query",
            "description": "Breakdown dimension: Service (default), Client, AssignedUser, or Month",
            "schema": {
              "enum": [
                "Service",
                "Client",
                "AssignedUser",
                "Month"
              ],
              "type": "string"
            }
          },
          {
            "name": "includeSkipped",
            "in": "query",
            "description": "Count Skipped tasks as delivered alongside Completed ones (default false)",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "service",
            "in": "query",
            "description": "Filter by billable service code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"SRV-001\" ]"
            }
          },
          {
            "name": "client",
            "in": "query",
            "description": "Filter by client code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"CLI-001\" ]"
            }
          },
          {
            "name": "user",
            "in": "query",
            "description": "Filter by assigned user code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"USR-001\" ]"
            }
          },
          {
            "name": "team",
            "in": "query",
            "description": "Filter by assigned team code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"payroll-team\" ]"
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "Filter by task category code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"CAT-001\" ]"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceDeliveryStepsDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/reports/service-delivery/csv": {
      "get": {
        "tags": [
          "Reports"
        ],
        "summary": "Export Service Delivery Report",
        "description": "The breakdown table as a CSV download - same filters and grouping as the report endpoint.",
        "operationId": "GetServiceDeliveryReportCsv",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "dateRange",
            "in": "query",
            "description": "Preset date range for the completion window (default Last30Days). If CustomDateRange, startDate and endDate are required.",
            "schema": {
              "enum": [
                "ThisWeek",
                "NextWeek",
                "Last7Days",
                "Next7Days",
                "Last30Days",
                "Next30Days",
                "PreviousMonth",
                "ThisMonth",
                "NextMonth",
                "PreviousQuarter",
                "ThisQuarter",
                "NextQuarter",
                "PreviousYear",
                "ThisYear",
                "NextYear",
                "YearToDate",
                "PreviousFinancialYear",
                "ThisFinancialYear",
                "NextFinancialYear",
                "FinancialYearToDate",
                "Today",
                "CustomDateRange"
              ],
              "type": "string"
            }
          },
          {
            "name": "startDate",
            "in": "query",
            "description": "Completion window start (inclusive). Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "description": "Completion window end (inclusive). Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "groupBy",
            "in": "query",
            "description": "Breakdown dimension: Service (default), Client, AssignedUser, or Month",
            "schema": {
              "enum": [
                "Service",
                "Client",
                "AssignedUser",
                "Month"
              ],
              "type": "string"
            }
          },
          {
            "name": "includeSkipped",
            "in": "query",
            "description": "Count Skipped tasks as delivered alongside Completed ones (default false)",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "service",
            "in": "query",
            "description": "Filter by billable service code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"SRV-001\" ]"
            }
          },
          {
            "name": "client",
            "in": "query",
            "description": "Filter by client code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"CLI-001\" ]"
            }
          },
          {
            "name": "user",
            "in": "query",
            "description": "Filter by assigned user code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"USR-001\" ]"
            }
          },
          {
            "name": "team",
            "in": "query",
            "description": "Filter by assigned team code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"payroll-team\" ]"
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "Filter by task category code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"CAT-001\" ]"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/reports/deadline-compliance": {
      "get": {
        "tags": [
          "Reports"
        ],
        "summary": "Get Deadline Compliance Report",
        "description": "Which deadlines did we miss, and which are we about to? The cohort is every non-Skipped task whose chosen deadline (due date, or statutory due date via deadlineType) fell in the window - met / completed-late / missed-still-open / pending - grouped by service, client, assignee, or deadline month, plus the forward-looking days-remaining buckets over currently-open work.",
        "operationId": "GetDeadlineComplianceReport",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "dateRange",
            "in": "query",
            "description": "Preset date range for the deadline window (default Last30Days). If CustomDateRange, startDate and endDate are required.",
            "schema": {
              "enum": [
                "ThisWeek",
                "NextWeek",
                "Last7Days",
                "Next7Days",
                "Last30Days",
                "Next30Days",
                "PreviousMonth",
                "ThisMonth",
                "NextMonth",
                "PreviousQuarter",
                "ThisQuarter",
                "NextQuarter",
                "PreviousYear",
                "ThisYear",
                "NextYear",
                "YearToDate",
                "PreviousFinancialYear",
                "ThisFinancialYear",
                "NextFinancialYear",
                "FinancialYearToDate",
                "Today",
                "CustomDateRange"
              ],
              "type": "string"
            }
          },
          {
            "name": "startDate",
            "in": "query",
            "description": "Deadline window start (inclusive). Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "description": "Deadline window end (inclusive). Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "groupBy",
            "in": "query",
            "description": "Breakdown dimension: Service (default), Client, AssignedUser, or Month",
            "schema": {
              "enum": [
                "Service",
                "Client",
                "AssignedUser",
                "Month"
              ],
              "type": "string"
            }
          },
          {
            "name": "deadlineType",
            "in": "query",
            "description": "Deadline to measure against: DueDate (default) or StatutoryDueDate (restricts to tasks that have one)",
            "schema": {
              "enum": [
                "DueDate",
                "StatutoryDueDate"
              ],
              "type": "string"
            }
          },
          {
            "name": "service",
            "in": "query",
            "description": "Filter by billable service code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"SRV-001\" ]"
            }
          },
          {
            "name": "client",
            "in": "query",
            "description": "Filter by client code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"CLI-001\" ]"
            }
          },
          {
            "name": "user",
            "in": "query",
            "description": "Filter by assigned user code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"USR-001\" ]"
            }
          },
          {
            "name": "team",
            "in": "query",
            "description": "Filter by assigned team code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"payroll-team\" ]"
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "Filter by task category code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"CAT-001\" ]"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeadlineComplianceReportDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/reports/deadline-compliance/csv": {
      "get": {
        "tags": [
          "Reports"
        ],
        "summary": "Export Deadline Compliance Report",
        "description": "The breakdown table as a CSV download - same filters and grouping as the report endpoint.",
        "operationId": "GetDeadlineComplianceReportCsv",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "dateRange",
            "in": "query",
            "description": "Preset date range for the deadline window (default Last30Days). If CustomDateRange, startDate and endDate are required.",
            "schema": {
              "enum": [
                "ThisWeek",
                "NextWeek",
                "Last7Days",
                "Next7Days",
                "Last30Days",
                "Next30Days",
                "PreviousMonth",
                "ThisMonth",
                "NextMonth",
                "PreviousQuarter",
                "ThisQuarter",
                "NextQuarter",
                "PreviousYear",
                "ThisYear",
                "NextYear",
                "YearToDate",
                "PreviousFinancialYear",
                "ThisFinancialYear",
                "NextFinancialYear",
                "FinancialYearToDate",
                "Today",
                "CustomDateRange"
              ],
              "type": "string"
            }
          },
          {
            "name": "startDate",
            "in": "query",
            "description": "Deadline window start (inclusive). Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "description": "Deadline window end (inclusive). Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "groupBy",
            "in": "query",
            "description": "Breakdown dimension: Service (default), Client, AssignedUser, or Month",
            "schema": {
              "enum": [
                "Service",
                "Client",
                "AssignedUser",
                "Month"
              ],
              "type": "string"
            }
          },
          {
            "name": "deadlineType",
            "in": "query",
            "description": "Deadline to measure against: DueDate (default) or StatutoryDueDate (restricts to tasks that have one)",
            "schema": {
              "enum": [
                "DueDate",
                "StatutoryDueDate"
              ],
              "type": "string"
            }
          },
          {
            "name": "service",
            "in": "query",
            "description": "Filter by billable service code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"SRV-001\" ]"
            }
          },
          {
            "name": "client",
            "in": "query",
            "description": "Filter by client code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"CLI-001\" ]"
            }
          },
          {
            "name": "user",
            "in": "query",
            "description": "Filter by assigned user code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"USR-001\" ]"
            }
          },
          {
            "name": "team",
            "in": "query",
            "description": "Filter by assigned team code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"payroll-team\" ]"
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "Filter by task category code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"CAT-001\" ]"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/reports/client-responsiveness": {
      "get": {
        "tags": [
          "Reports"
        ],
        "summary": "Get Client Responsiveness Report",
        "description": "Is it us or the client: response times and chase pressure over client-facing workflow steps (confirmations, document requests, data forms, approvals) completed in the window, grouped by client, service, or step type, plus the currently-outstanding snapshot.",
        "operationId": "GetClientResponsivenessReport",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "dateRange",
            "in": "query",
            "description": "Preset date range for the step-completion window (default Last30Days). If CustomDateRange, startDate and endDate are required.",
            "schema": {
              "enum": [
                "ThisWeek",
                "NextWeek",
                "Last7Days",
                "Next7Days",
                "Last30Days",
                "Next30Days",
                "PreviousMonth",
                "ThisMonth",
                "NextMonth",
                "PreviousQuarter",
                "ThisQuarter",
                "NextQuarter",
                "PreviousYear",
                "ThisYear",
                "NextYear",
                "YearToDate",
                "PreviousFinancialYear",
                "ThisFinancialYear",
                "NextFinancialYear",
                "FinancialYearToDate",
                "Today",
                "CustomDateRange"
              ],
              "type": "string"
            }
          },
          {
            "name": "startDate",
            "in": "query",
            "description": "Step-completion window start (inclusive). Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "description": "Step-completion window end (inclusive). Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "groupBy",
            "in": "query",
            "description": "Breakdown dimension: Client (default), Service, or StepType",
            "schema": {
              "enum": [
                "Client",
                "Service",
                "StepType"
              ],
              "type": "string"
            }
          },
          {
            "name": "service",
            "in": "query",
            "description": "Filter by billable service code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"SRV-001\" ]"
            }
          },
          {
            "name": "client",
            "in": "query",
            "description": "Filter by client code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"CLI-001\" ]"
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "Filter by task category code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"CAT-001\" ]"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientResponsivenessReportDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/reports/client-responsiveness/csv": {
      "get": {
        "tags": [
          "Reports"
        ],
        "summary": "Export Client Responsiveness Report",
        "description": "The breakdown table as a CSV download - same filters and grouping as the report endpoint.",
        "operationId": "GetClientResponsivenessReportCsv",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "dateRange",
            "in": "query",
            "description": "Preset date range for the step-completion window (default Last30Days). If CustomDateRange, startDate and endDate are required.",
            "schema": {
              "enum": [
                "ThisWeek",
                "NextWeek",
                "Last7Days",
                "Next7Days",
                "Last30Days",
                "Next30Days",
                "PreviousMonth",
                "ThisMonth",
                "NextMonth",
                "PreviousQuarter",
                "ThisQuarter",
                "NextQuarter",
                "PreviousYear",
                "ThisYear",
                "NextYear",
                "YearToDate",
                "PreviousFinancialYear",
                "ThisFinancialYear",
                "NextFinancialYear",
                "FinancialYearToDate",
                "Today",
                "CustomDateRange"
              ],
              "type": "string"
            }
          },
          {
            "name": "startDate",
            "in": "query",
            "description": "Step-completion window start (inclusive). Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "description": "Step-completion window end (inclusive). Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "groupBy",
            "in": "query",
            "description": "Breakdown dimension: Client (default), Service, or StepType",
            "schema": {
              "enum": [
                "Client",
                "Service",
                "StepType"
              ],
              "type": "string"
            }
          },
          {
            "name": "service",
            "in": "query",
            "description": "Filter by billable service code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"SRV-001\" ]"
            }
          },
          {
            "name": "client",
            "in": "query",
            "description": "Filter by client code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"CLI-001\" ]"
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "Filter by task category code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"CAT-001\" ]"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/reports/team-workload": {
      "get": {
        "tags": [
          "Reports"
        ],
        "summary": "Get Team Workload Report",
        "description": "Who's overloaded and who completes what: the open-workload snapshot per assignee (open, overdue, blocked) plus completion throughput over the window (completions, average turnaround, on-time rate). Group by user (completions attributed to who completed the task) or team.",
        "operationId": "GetTeamWorkloadReport",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "dateRange",
            "in": "query",
            "description": "Preset date range for the completion window (default Last30Days). If CustomDateRange, startDate and endDate are required. Open-workload counts are always a now snapshot.",
            "schema": {
              "enum": [
                "ThisWeek",
                "NextWeek",
                "Last7Days",
                "Next7Days",
                "Last30Days",
                "Next30Days",
                "PreviousMonth",
                "ThisMonth",
                "NextMonth",
                "PreviousQuarter",
                "ThisQuarter",
                "NextQuarter",
                "PreviousYear",
                "ThisYear",
                "NextYear",
                "YearToDate",
                "PreviousFinancialYear",
                "ThisFinancialYear",
                "NextFinancialYear",
                "FinancialYearToDate",
                "Today",
                "CustomDateRange"
              ],
              "type": "string"
            }
          },
          {
            "name": "startDate",
            "in": "query",
            "description": "Completion window start (inclusive). Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "description": "Completion window end (inclusive). Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "groupBy",
            "in": "query",
            "description": "Breakdown dimension: User (default) or Team",
            "schema": {
              "enum": [
                "User",
                "Team"
              ],
              "type": "string"
            }
          },
          {
            "name": "service",
            "in": "query",
            "description": "Filter by billable service code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"SRV-001\" ]"
            }
          },
          {
            "name": "client",
            "in": "query",
            "description": "Filter by client code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"CLI-001\" ]"
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "Filter by task category code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"CAT-001\" ]"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TeamWorkloadReportDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/reports/team-workload/csv": {
      "get": {
        "tags": [
          "Reports"
        ],
        "summary": "Export Team Workload Report",
        "description": "The breakdown table as a CSV download - same filters and grouping as the report endpoint.",
        "operationId": "GetTeamWorkloadReportCsv",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "dateRange",
            "in": "query",
            "description": "Preset date range for the completion window (default Last30Days). If CustomDateRange, startDate and endDate are required. Open-workload counts are always a now snapshot.",
            "schema": {
              "enum": [
                "ThisWeek",
                "NextWeek",
                "Last7Days",
                "Next7Days",
                "Last30Days",
                "Next30Days",
                "PreviousMonth",
                "ThisMonth",
                "NextMonth",
                "PreviousQuarter",
                "ThisQuarter",
                "NextQuarter",
                "PreviousYear",
                "ThisYear",
                "NextYear",
                "YearToDate",
                "PreviousFinancialYear",
                "ThisFinancialYear",
                "NextFinancialYear",
                "FinancialYearToDate",
                "Today",
                "CustomDateRange"
              ],
              "type": "string"
            }
          },
          {
            "name": "startDate",
            "in": "query",
            "description": "Completion window start (inclusive). Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "description": "Completion window end (inclusive). Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "groupBy",
            "in": "query",
            "description": "Breakdown dimension: User (default) or Team",
            "schema": {
              "enum": [
                "User",
                "Team"
              ],
              "type": "string"
            }
          },
          {
            "name": "service",
            "in": "query",
            "description": "Filter by billable service code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"SRV-001\" ]"
            }
          },
          {
            "name": "client",
            "in": "query",
            "description": "Filter by client code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"CLI-001\" ]"
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "Filter by task category code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"CAT-001\" ]"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/reports/wip-ageing": {
      "get": {
        "tags": [
          "Reports"
        ],
        "summary": "Get WIP Ageing Report",
        "description": "What's sitting untouched: a point-in-time snapshot of open tasks whose planned start has arrived, grouped by age bucket, status, service, client, assignee, or current workflow step. No date range - age is measured from planned start to today.",
        "operationId": "GetWipAgeingReport",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "groupBy",
            "in": "query",
            "description": "Breakdown dimension: AgeBucket (default), Status, Service, Client, AssignedUser, or CurrentStep",
            "schema": {
              "enum": [
                "AgeBucket",
                "Status",
                "Service",
                "Client",
                "AssignedUser",
                "CurrentStep"
              ],
              "type": "string"
            }
          },
          {
            "name": "service",
            "in": "query",
            "description": "Filter by billable service code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"SRV-001\" ]"
            }
          },
          {
            "name": "client",
            "in": "query",
            "description": "Filter by client code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"CLI-001\" ]"
            }
          },
          {
            "name": "user",
            "in": "query",
            "description": "Filter by assigned user code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"USR-001\" ]"
            }
          },
          {
            "name": "team",
            "in": "query",
            "description": "Filter by assigned team code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"payroll-team\" ]"
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "Filter by task category code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"CAT-001\" ]"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WipAgeingReportDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/reports/wip-ageing/csv": {
      "get": {
        "tags": [
          "Reports"
        ],
        "summary": "Export WIP Ageing Report",
        "description": "The breakdown table as a CSV download - same filters and grouping as the report endpoint.",
        "operationId": "GetWipAgeingReportCsv",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "groupBy",
            "in": "query",
            "description": "Breakdown dimension: AgeBucket (default), Status, Service, Client, AssignedUser, or CurrentStep",
            "schema": {
              "enum": [
                "AgeBucket",
                "Status",
                "Service",
                "Client",
                "AssignedUser",
                "CurrentStep"
              ],
              "type": "string"
            }
          },
          {
            "name": "service",
            "in": "query",
            "description": "Filter by billable service code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"SRV-001\" ]"
            }
          },
          {
            "name": "client",
            "in": "query",
            "description": "Filter by client code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"CLI-001\" ]"
            }
          },
          {
            "name": "user",
            "in": "query",
            "description": "Filter by assigned user code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"USR-001\" ]"
            }
          },
          {
            "name": "team",
            "in": "query",
            "description": "Filter by assigned team code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"payroll-team\" ]"
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "Filter by task category code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"CAT-001\" ]"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/reports/workflow-steps": {
      "get": {
        "tags": [
          "Reports"
        ],
        "summary": "Get Workflow Step Analysis Report",
        "description": "For one workflow template, where does the time go? Per-step duration distributions (median/avg/best/worst/p90, active vs elapsed, skips, chases, client-wait vs internal) across every occurrence (task) spawned from the workflow and completed in the window, divided into the workflow's groups. The occurrence list is served separately (paged) by the occurrences endpoint.",
        "operationId": "GetWorkflowStepAnalysisReport",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "workflowCode",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "dateRange",
            "in": "query",
            "description": "Preset date range for the task-completion window (default Last30Days). If CustomDateRange, startDate and endDate are required.",
            "schema": {
              "enum": [
                "ThisWeek",
                "NextWeek",
                "Last7Days",
                "Next7Days",
                "Last30Days",
                "Next30Days",
                "PreviousMonth",
                "ThisMonth",
                "NextMonth",
                "PreviousQuarter",
                "ThisQuarter",
                "NextQuarter",
                "PreviousYear",
                "ThisYear",
                "NextYear",
                "YearToDate",
                "PreviousFinancialYear",
                "ThisFinancialYear",
                "NextFinancialYear",
                "FinancialYearToDate",
                "Today",
                "CustomDateRange"
              ],
              "type": "string"
            }
          },
          {
            "name": "startDate",
            "in": "query",
            "description": "Task-completion window start (inclusive). Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "description": "Task-completion window end (inclusive). Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowStepAnalysisReportDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/reports/workflow-steps/occurrences": {
      "get": {
        "tags": [
          "Reports"
        ],
        "summary": "List Workflow Step Analysis Occurrences",
        "description": "One page of the Workflow Step Analysis occurrence list - one row per task spawned from the workflow and completed in the window, slowest first, with the client-wait vs internal split. Standard offset/limit paging.",
        "operationId": "GetWorkflowStepAnalysisOccurrences",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "workflowCode",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "dateRange",
            "in": "query",
            "description": "Preset date range for the task-completion window (default Last30Days). If CustomDateRange, startDate and endDate are required.",
            "schema": {
              "enum": [
                "ThisWeek",
                "NextWeek",
                "Last7Days",
                "Next7Days",
                "Last30Days",
                "Next30Days",
                "PreviousMonth",
                "ThisMonth",
                "NextMonth",
                "PreviousQuarter",
                "ThisQuarter",
                "NextQuarter",
                "PreviousYear",
                "ThisYear",
                "NextYear",
                "YearToDate",
                "PreviousFinancialYear",
                "ThisFinancialYear",
                "NextFinancialYear",
                "FinancialYearToDate",
                "Today",
                "CustomDateRange"
              ],
              "type": "string"
            }
          },
          {
            "name": "startDate",
            "in": "query",
            "description": "Task-completion window start (inclusive). Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "description": "Task-completion window end (inclusive). Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowOccurrenceDtoPagedResult"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/reports/service-time": {
      "get": {
        "tags": [
          "Reports"
        ],
        "summary": "Get Service Time Report",
        "description": "Estimated vs actual time per service: total minutes logged in the window attributed to services via each entry's linked task, compared against the service's estimated minutes per engagement. Pass serviceCode to drill into one service and see the per-client breakdown. Requires time tracking to be in use.",
        "operationId": "GetServiceTimeReport",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "dateRange",
            "in": "query",
            "description": "Preset date range for the time entry window (default Last30Days). If CustomDateRange, startDate and endDate are required.",
            "schema": {
              "enum": [
                "ThisWeek",
                "NextWeek",
                "Last7Days",
                "Next7Days",
                "Last30Days",
                "Next30Days",
                "PreviousMonth",
                "ThisMonth",
                "NextMonth",
                "PreviousQuarter",
                "ThisQuarter",
                "NextQuarter",
                "PreviousYear",
                "ThisYear",
                "NextYear",
                "YearToDate",
                "PreviousFinancialYear",
                "ThisFinancialYear",
                "NextFinancialYear",
                "FinancialYearToDate",
                "Today",
                "CustomDateRange"
              ],
              "type": "string"
            }
          },
          {
            "name": "startDate",
            "in": "query",
            "description": "Entry window start (inclusive). Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "description": "Entry window end (inclusive). Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceCode",
            "in": "query",
            "description": "Drill into one service - rows group by client instead of by service",
            "schema": {
              "type": "string",
              "example": "annual-accounts"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceTimeReportDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/reports/service-time/csv": {
      "get": {
        "tags": [
          "Reports"
        ],
        "summary": "Export Service Time Report",
        "description": "The breakdown table as a CSV download - same filters as the report endpoint.",
        "operationId": "GetServiceTimeReportCsv",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "dateRange",
            "in": "query",
            "description": "Preset date range for the time entry window (default Last30Days). If CustomDateRange, startDate and endDate are required.",
            "schema": {
              "enum": [
                "ThisWeek",
                "NextWeek",
                "Last7Days",
                "Next7Days",
                "Last30Days",
                "Next30Days",
                "PreviousMonth",
                "ThisMonth",
                "NextMonth",
                "PreviousQuarter",
                "ThisQuarter",
                "NextQuarter",
                "PreviousYear",
                "ThisYear",
                "NextYear",
                "YearToDate",
                "PreviousFinancialYear",
                "ThisFinancialYear",
                "NextFinancialYear",
                "FinancialYearToDate",
                "Today",
                "CustomDateRange"
              ],
              "type": "string"
            }
          },
          {
            "name": "startDate",
            "in": "query",
            "description": "Entry window start (inclusive). Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "description": "Entry window end (inclusive). Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serviceCode",
            "in": "query",
            "description": "Drill into one service - rows group by client instead of by service",
            "schema": {
              "type": "string",
              "example": "annual-accounts"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/reports/workflow-steps/csv": {
      "get": {
        "tags": [
          "Reports"
        ],
        "summary": "Export Workflow Step Analysis Report",
        "description": "The per-step table as a CSV download - same filters as the report endpoint.",
        "operationId": "GetWorkflowStepAnalysisReportCsv",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "workflowCode",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "dateRange",
            "in": "query",
            "description": "Preset date range for the task-completion window (default Last30Days). If CustomDateRange, startDate and endDate are required.",
            "schema": {
              "enum": [
                "ThisWeek",
                "NextWeek",
                "Last7Days",
                "Next7Days",
                "Last30Days",
                "Next30Days",
                "PreviousMonth",
                "ThisMonth",
                "NextMonth",
                "PreviousQuarter",
                "ThisQuarter",
                "NextQuarter",
                "PreviousYear",
                "ThisYear",
                "NextYear",
                "YearToDate",
                "PreviousFinancialYear",
                "ThisFinancialYear",
                "NextFinancialYear",
                "FinancialYearToDate",
                "Today",
                "CustomDateRange"
              ],
              "type": "string"
            }
          },
          {
            "name": "startDate",
            "in": "query",
            "description": "Task-completion window start (inclusive). Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "description": "Task-completion window end (inclusive). Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/revenue-ranges": {
      "get": {
        "tags": [
          "Revenue Ranges"
        ],
        "summary": "List RevenueRanges",
        "description": "Lists all RevenueRanges for the given tenant.",
        "operationId": "ListRevenueRanges",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/RevenueRangeSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search term to filter results",
            "schema": {
              "type": "string",
              "example": "keyword"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RevenueRangeDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Revenue Ranges"
        ],
        "summary": "Create RevenueRange",
        "description": "Creates a new RevenueRange for the specified tenant.",
        "operationId": "CreateRevenueRange",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateRevenueRangeRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RevenueRangeDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/revenue-ranges/{code}": {
      "get": {
        "tags": [
          "Revenue Ranges"
        ],
        "summary": "Get RevenueRange",
        "description": "Gets a RevenueRange for the specified tenant.",
        "operationId": "GetRevenueRange",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RevenueRangeDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Revenue Ranges"
        ],
        "summary": "Update RevenueRange",
        "description": "Updates a RevenueRange for the specified tenant.",
        "operationId": "UpdateRevenueRange",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateRevenueRangeRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RevenueRangeDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Revenue Ranges"
        ],
        "summary": "Delete RevenueRange",
        "description": "Deletes a RevenueRange for the specified tenant.",
        "operationId": "DeleteRevenueRange",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/sales-pipeline-settings": {
      "get": {
        "tags": [
          "Sales Pipeline - Settings"
        ],
        "summary": "Get sales pipeline settings",
        "description": "Returns the sales pipeline settings for the specified tenant",
        "operationId": "GetSalesPipeline-Settings",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SalesPipelineSettingsDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "put": {
        "tags": [
          "Sales Pipeline - Settings"
        ],
        "summary": "Update sales pipeline settings",
        "description": "Updates the sales pipeline settings (enable/disable the feature) for the specified tenant",
        "operationId": "UpdateSalesPipeline-Settings",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateSalesPipelineSettingsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SalesPipelineSettingsDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/onboarding-task-templates": {
      "get": {
        "tags": [
          "Service - Onboarding Tasks"
        ],
        "summary": "List OnboardingTaskTemplates",
        "description": "Lists all OnboardingTaskTemplates for the given tenant.",
        "operationId": "ListOnboardingTaskTemplates",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/OnboardingTaskTemplateSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "serviceCode",
            "in": "query",
            "description": "Filter by billable service code",
            "schema": {
              "type": "string",
              "example": "VAT-001"
            }
          },
          {
            "name": "isActive",
            "in": "query",
            "description": "Filter by active status (true = active only, false = inactive only)",
            "schema": {
              "type": "boolean",
              "example": "true"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search across template code, name, and description (minimum 3 characters)",
            "schema": {
              "type": "string",
              "example": "vat"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OnboardingTaskTemplateDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Service - Onboarding Tasks"
        ],
        "summary": "Create OnboardingTaskTemplate",
        "description": "Creates a new OnboardingTaskTemplate for the specified tenant.",
        "operationId": "CreateOnboardingTaskTemplate",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateOnboardingTaskTemplateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OnboardingTaskTemplateDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/onboarding-task-templates/{code}": {
      "get": {
        "tags": [
          "Service - Onboarding Tasks"
        ],
        "summary": "Get OnboardingTaskTemplate",
        "description": "Gets a OnboardingTaskTemplate for the specified tenant.",
        "operationId": "GetOnboardingTaskTemplate",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OnboardingTaskTemplateDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Service - Onboarding Tasks"
        ],
        "summary": "Update OnboardingTaskTemplate",
        "description": "Updates a OnboardingTaskTemplate for the specified tenant.",
        "operationId": "UpdateOnboardingTaskTemplate",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateOnboardingTaskTemplateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OnboardingTaskTemplateDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Service - Onboarding Tasks"
        ],
        "summary": "Delete OnboardingTaskTemplate",
        "description": "Deletes a OnboardingTaskTemplate for the specified tenant.",
        "operationId": "DeleteOnboardingTaskTemplate",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/onboarding-task-templates/{code}/library-version": {
      "put": {
        "tags": [
          "Service - Onboarding Tasks"
        ],
        "summary": "Revert OnboardingTaskTemplate to Library",
        "description": "Reverts the OnboardingTaskTemplate to the current library template version, overwriting any local edits. The OnboardingTaskTemplate's code is preserved so it remains addressable at the same URL. Returns 400 if the OnboardingTaskTemplate was not imported from the library, or 404 if the OnboardingTaskTemplate or its source library template no longer exists.",
        "operationId": "RevertOnboardingTaskTemplateToLibraryVersion",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OnboardingTaskTemplateDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/service-packages": {
      "get": {
        "tags": [
          "Service - Packages"
        ],
        "summary": "List ServicePackages",
        "description": "Lists all ServicePackages for the given tenant.",
        "operationId": "ListServicePackages",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/ServicePackageSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "service",
            "in": "query",
            "description": "Filter by billable service code(s) - returns packages containing any of the specified services",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"SVC-001\", \"SVC-002\" ]"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search term to filter results",
            "schema": {
              "type": "string",
              "example": "keyword"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServicePackageDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Service - Packages"
        ],
        "summary": "Create ServicePackage",
        "description": "Creates a new ServicePackage for the specified tenant.",
        "operationId": "CreateServicePackage",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateServicePackageRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServicePackageDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/service-packages/{code}": {
      "get": {
        "tags": [
          "Service - Packages"
        ],
        "summary": "Get ServicePackage",
        "description": "Gets a ServicePackage for the specified tenant.",
        "operationId": "GetServicePackage",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServicePackageDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Service - Packages"
        ],
        "summary": "Update ServicePackage",
        "description": "Updates a ServicePackage for the specified tenant.",
        "operationId": "UpdateServicePackage",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateServicePackageRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServicePackageDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Service - Packages"
        ],
        "summary": "Delete ServicePackage",
        "description": "Deletes a ServicePackage for the specified tenant.",
        "operationId": "DeleteServicePackage",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/service-packages/{code}/bulk-apply": {
      "post": {
        "tags": [
          "Service - Packages"
        ],
        "summary": "Bulk Apply Package",
        "description": "Applies this service package to multiple clients at once. Creates ClientBillableService records for each package item for each client.",
        "operationId": "BulkApplyServicePackageToClients",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkApplyServicePackageRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkAssignResult"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/clients/{clientCode}/apply-service-package/{packageCode}": {
      "post": {
        "tags": [
          "Service - Packages"
        ],
        "summary": "Apply Service Package to Client",
        "description": "Applies a service package to a client, creating ClientBillableService records for each item in the package.",
        "operationId": "ApplyServicePackageToClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "clientCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 213
          },
          {
            "name": "packageCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApplyServicePackageRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ClientBillableServiceDto"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Service - Packages"
        ],
        "summary": "Remove Service Package from Client",
        "description": "Removes all client billable services linked to the specified service package.",
        "operationId": "RemoveServicePackageFromClient",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "clientCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 213
          },
          {
            "name": "packageCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/services": {
      "get": {
        "tags": [
          "Services"
        ],
        "summary": "List BillableServices",
        "description": "Lists all BillableServices for the given tenant.",
        "operationId": "ListBillableServices",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/BillableServiceSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "category",
            "in": "query",
            "description": "Filter services by category",
            "schema": {
              "enum": [
                "Other",
                "CoreAccounting",
                "Tax",
                "Payroll",
                "CompanySecretarial",
                "Advisory",
                "SoftwareAndTraining"
              ],
              "type": "string",
              "example": "CoreAccounting"
            }
          },
          {
            "name": "clientType",
            "in": "query",
            "description": "Filter services by client type they are applicable to",
            "schema": {
              "enum": [
                "PrivateLimitedCompany",
                "PublicLimitedCompany",
                "LimitedLiabilityPartnership",
                "Partnership",
                "Individual",
                "Trust",
                "Charity",
                "SoleTrader"
              ],
              "type": "string",
              "example": "Individual"
            }
          },
          {
            "name": "isArchived",
            "in": "query",
            "description": "Filter by archived status (true = archived only, false = active only)",
            "schema": {
              "type": "boolean",
              "example": "false"
            }
          },
          {
            "name": "hasStages",
            "in": "query",
            "description": "Filter to only services that have stages defined (true = with stages only)",
            "schema": {
              "type": "boolean",
              "example": "true"
            }
          },
          {
            "name": "showKanbanBoard",
            "in": "query",
            "description": "Filter to only services with kanban board enabled (true = kanban-enabled only)",
            "schema": {
              "type": "boolean",
              "example": "true"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search across service code and name (minimum 3 characters)",
            "schema": {
              "type": "string",
              "example": "tax"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillableServiceDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Services"
        ],
        "summary": "Create BillableService",
        "description": "Creates a new BillableService for the specified tenant.",
        "operationId": "CreateBillableService",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateBillableServiceRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillableServiceDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/services/{code}": {
      "get": {
        "tags": [
          "Services"
        ],
        "summary": "Get BillableService",
        "description": "Gets a BillableService for the specified tenant.",
        "operationId": "GetBillableService",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillableServiceDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Services"
        ],
        "summary": "Update BillableService",
        "description": "Updates a BillableService for the specified tenant.",
        "operationId": "UpdateBillableService",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateBillableServiceRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillableServiceDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Services"
        ],
        "summary": "Delete BillableService",
        "description": "Deletes a BillableService for the specified tenant.",
        "operationId": "DeleteBillableService",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/services/library": {
      "get": {
        "tags": [
          "Services"
        ],
        "summary": "List Library BillableServices",
        "description": "List all BillableServices available in the library as templates. Use optional 'search' query parameter to filter by Code, Name, or Description.",
        "operationId": "ListLibraryBillableServices",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 150
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/BillableServiceDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/services/library/{code}": {
      "get": {
        "tags": [
          "Services"
        ],
        "summary": "Get Library BillableService",
        "description": "Get details of a specific BillableService template from the library",
        "operationId": "GetLibraryBillableService",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillableServiceDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/services/{code}/library-version": {
      "put": {
        "tags": [
          "Services"
        ],
        "summary": "Revert BillableService to Library",
        "description": "Reverts the BillableService to the current library template version, overwriting any local edits. The BillableService's code is preserved so it remains addressable at the same URL. Returns 400 if the BillableService was not imported from the library, or 404 if the BillableService or its source library template no longer exists.",
        "operationId": "RevertBillableServiceToLibraryVersion",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillableServiceDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/services/library/import": {
      "post": {
        "tags": [
          "Services"
        ],
        "summary": "Import Services from Library",
        "description": "Creates one or more BillableServices for the tenant based on library templates.",
        "operationId": "ImportBillableServicesFromLibrary",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImportBillableServicesFromLibraryRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/BillableServiceDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/services/generate": {
      "post": {
        "tags": [
          "Services"
        ],
        "summary": "Generate Service",
        "description": "Generates a complete BillableService DTO with AI-generated content based on the service name",
        "operationId": "GenerateBillableService",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateBillableServiceRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillableServiceDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/services/{code}/generatefactors": {
      "post": {
        "tags": [
          "Services"
        ],
        "summary": "Generate Pricing Factors",
        "description": "Generates pricing factor questions and options for an existing service using AI",
        "operationId": "GeneratePricingFactors",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PricingFactorDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/services/{code}/required-client-fields": {
      "get": {
        "tags": [
          "Services"
        ],
        "summary": "Get Required Client Fields for Service",
        "description": "Returns client fields that are required by recurring tasks linked to this service.",
        "operationId": "GetRequiredClientFieldsForService",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ClientCsvTargetField"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/services/{code}/clients/bulk-assign": {
      "post": {
        "tags": [
          "Services"
        ],
        "summary": "Bulk Assign Service",
        "description": "Assigns this billable service to multiple clients at once. Optionally creates onboarding tasks for each new assignment.",
        "operationId": "BulkAssignServiceToClients",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkAssignServiceRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkAssignResult"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/services/{code}/clients/bulk-update": {
      "patch": {
        "tags": [
          "Services"
        ],
        "summary": "Bulk Update Client Services",
        "description": "Updates fields across multiple client service assignments. Only provided (non-null) fields are changed.",
        "operationId": "BulkUpdateClientServices",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkUpdateClientServicesRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceBulkUpdateResult"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/services/{code}/clients/bulk-remove": {
      "post": {
        "tags": [
          "Services"
        ],
        "summary": "Bulk Remove Client Services",
        "description": "Removes multiple client service assignments. Fails if any have billing line items.",
        "operationId": "BulkRemoveClientServices",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkRemoveClientServicesRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkDeleteResult"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/subscription": {
      "get": {
        "tags": [
          "Subscription"
        ],
        "summary": "Get Current Subscription",
        "description": "Returns the current active subscription for the tenant",
        "operationId": "GetCurrentSubscription",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubscriptionDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "put": {
        "tags": [
          "Subscription"
        ],
        "summary": "Change Subscription",
        "description": "Changes the tenant's subscription to a different package. The pricing tier is automatically determined based on the tenant's active client count. If the subscription was previously cancelled, choosing a new package will clear the cancellation.",
        "operationId": "ChangeSubscription",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChangeSubscriptionRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubscriptionDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "delete": {
        "tags": [
          "Subscription"
        ],
        "summary": "Cancel Subscription",
        "description": "Cancels the tenant's subscription. During a free trial, this removes the pending package selection (the trial continues and will expire naturally). Outside of a trial, this ends the current subscription immediately and marks the tenant as cancelled — the tenant will be auto-downgraded to the appropriate tier based on their client count. To reactivate after cancellation, choose a new package via PUT which clears the cancellation flag.",
        "operationId": "CancelSubscription",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubscriptionDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/subscription/history": {
      "get": {
        "tags": [
          "Subscription"
        ],
        "summary": "Get Subscription History",
        "description": "Returns all subscriptions for the tenant, including historical",
        "operationId": "GetSubscriptionHistory",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/SubscriptionDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/subscription/price-preview": {
      "get": {
        "tags": [
          "Subscription"
        ],
        "summary": "Preview Subscription Prices",
        "description": "Returns the price for each available package based on the tenant's current active client count, including any active discount.",
        "operationId": "PreviewSubscriptionPrice",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/SubscriptionPricePreviewDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/subscription/user-billing": {
      "get": {
        "tags": [
          "Subscription"
        ],
        "summary": "Get User Billing Summary",
        "description": "Returns the tenant's per-user billing position: how many users are included in the subscription, the current billable user count (active and invited users), and the estimated monthly charge for any users above the included allowance.",
        "operationId": "GetUserBillingSummary",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserBillingSummaryDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/subscription/billing": {
      "get": {
        "tags": [
          "Subscription - Billing"
        ],
        "summary": "Get Billing Account",
        "description": "Returns the billing account linked to this tenant, or 404 if billing has not been set up.",
        "operationId": "GetBillingAccount",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingAccountResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "post": {
        "tags": [
          "Subscription - Billing"
        ],
        "summary": "Start Subscription Billing",
        "description": "Creates a billing account for the tenant. The billing account name is set from the tenant name and the billing contact is set to the current user.",
        "operationId": "StartSubscriptionBilling",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StartSubscriptionBillingRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingAccountResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "put": {
        "tags": [
          "Subscription - Billing"
        ],
        "summary": "Update Billing Account",
        "description": "Updates the billing account's address and invoice recipients. Name and billing contact are not changeable.",
        "operationId": "UpdateBillingAccount",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateSubscriptionBillingRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingAccountResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/subscription/billing/mandate-setup": {
      "post": {
        "tags": [
          "Subscription - Billing"
        ],
        "summary": "Initiate Mandate Setup",
        "description": "Starts a GoCardless Direct Debit mandate setup. Returns a URL to redirect the user to for authorisation.",
        "operationId": "InitiateMandateSetup",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InitiateMandateSetupRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MandateSetupResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/subscription/billing/mandate-setup/complete": {
      "post": {
        "tags": [
          "Subscription - Billing"
        ],
        "summary": "Complete Mandate Setup",
        "description": "Completes the GoCardless Direct Debit mandate setup after the user has authorised it.",
        "operationId": "CompleteMandateSetup",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CompleteMandateSetupRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentMandateResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/subscription/billing/mandate/cancel": {
      "post": {
        "tags": [
          "Subscription - Billing"
        ],
        "summary": "Cancel Mandate",
        "description": "Cancels the active Direct Debit mandate for the tenant's billing account.",
        "operationId": "CancelMandate",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/subscription/billing/mandate/refresh": {
      "get": {
        "tags": [
          "Subscription - Billing"
        ],
        "summary": "Refresh Mandate Status",
        "description": "Fetches the current mandate status from GoCardless and updates the local record.",
        "operationId": "RefreshMandateStatus",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentMandateResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/subscription/billing/invoices": {
      "get": {
        "tags": [
          "Subscription - Billing"
        ],
        "summary": "List Invoices",
        "description": "Returns a paginated list of invoices for the tenant's billing account with optional filtering by status and date range.",
        "operationId": "ListInvoices",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "status",
            "in": "query",
            "description": "Defines the status of a billing invoice.",
            "schema": {
              "$ref": "#/components/schemas/BillingInvoiceStatus"
            },
            "x-order": 200
          },
          {
            "name": "fromDate",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "x-order": 400
          },
          {
            "name": "toDate",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date"
            },
            "x-order": 400
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "type": "string"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceSummaryResponsePagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/subscription/billing/invoices/{code}/pdf": {
      "get": {
        "tags": [
          "Subscription - Billing"
        ],
        "summary": "Download Invoice PDF",
        "description": "Downloads the invoice PDF. Returns 404 if the PDF has not been generated.",
        "operationId": "DownloadInvoicePdf",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/subscription/billing/invoices/{code}": {
      "get": {
        "tags": [
          "Subscription - Billing"
        ],
        "summary": "Get Invoice",
        "description": "Returns the full invoice detail including line items. Use code 'draft' to get the current draft invoice.",
        "operationId": "GetInvoice",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/subscription/discount": {
      "get": {
        "tags": [
          "Subscription - Discounts"
        ],
        "summary": "Get Active Discount",
        "description": "Returns the currently active subscription discount for the tenant, or 404 if no discount is active.",
        "operationId": "GetActiveDiscount",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubscriptionDiscountDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "post": {
        "tags": [
          "Subscription - Discounts"
        ],
        "summary": "Redeem Discount Code",
        "description": "Redeems a discount code for this tenant's subscription billing. The tenant must not already have an active discount.",
        "operationId": "RedeemDiscountCode",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RedeemDiscountCodeRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubscriptionDiscountDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "delete": {
        "tags": [
          "Subscription - Discounts"
        ],
        "summary": "Remove Discount",
        "description": "Removes the active discount from this tenant, allowing a different discount code to be applied.",
        "operationId": "RemoveDiscount",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/tasks/{taskCode}/emails": {
      "get": {
        "tags": [
          "Task - Emails"
        ],
        "summary": "List Emails for Task",
        "description": "Returns email conversations that have been explicitly linked to this task.",
        "operationId": "GetTaskEmails",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "taskCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MailboxThreadSummaryDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/tasks/{taskCode}/taskitemnote": {
      "get": {
        "tags": [
          "Task - Notes"
        ],
        "summary": "List Notes for Task",
        "description": "Lists notes for the specified task. By default only returns task-level notes. Set includeStepNotes=true to also include notes attached to workflow steps.",
        "operationId": "ListTaskItemNotes",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 150
          },
          {
            "name": "includeStepNotes",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "x-order": 400
          },
          {
            "name": "taskCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/TaskItemNoteSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NoteDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Task - Notes"
        ],
        "summary": "Create Note",
        "description": "Creates a new note for the specified task.",
        "operationId": "CreateTaskItemNote",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "taskCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTaskItemNoteRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NoteDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/tasks/{taskCode}/taskitemnote/pinned": {
      "get": {
        "tags": [
          "Task - Notes"
        ],
        "summary": "Get Pinned Notes for Task",
        "description": "Gets pinned notes for the specified task (PinnedLevel > 0), ordered by PinnedLevel descending. By default only returns task-level pinned notes. Set includeStepNotes=true to also include notes attached to workflow steps.",
        "operationId": "GetPinnedTaskItemNotes",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "includeStepNotes",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "x-order": 400
          },
          {
            "name": "taskCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/NoteDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/tasks/{taskCode}/taskitemnote/{code}": {
      "get": {
        "tags": [
          "Task - Notes"
        ],
        "summary": "Get Note by Code",
        "description": "Gets a specific note for the task by its code.",
        "operationId": "GetTaskItemNote",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          },
          {
            "name": "taskCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NoteDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Task - Notes"
        ],
        "summary": "Update Note",
        "description": "Updates an existing note for the specified task.",
        "operationId": "UpdateTaskItemNote",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          },
          {
            "name": "taskCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTaskItemNoteRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NoteDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Task - Notes"
        ],
        "summary": "Delete Note",
        "description": "Deletes a note from the specified task.",
        "operationId": "DeleteTaskItemNote",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          },
          {
            "name": "taskCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/tasks/{taskCode}/groups/{groupNumber}/steps/{stepNumber}/notes": {
      "get": {
        "tags": [
          "Task - Workflow Notes"
        ],
        "summary": "List Notes for Workflow Step",
        "description": "Lists all notes for the specified workflow step.",
        "operationId": "ListStepNotes",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 150
          },
          {
            "name": "groupNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "x-order": 400
          },
          {
            "name": "stepNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "x-order": 400
          },
          {
            "name": "taskCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/TaskItemNoteSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NoteDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Task - Workflow Notes"
        ],
        "summary": "Create Note for Workflow Step",
        "description": "Creates a new note for the specified workflow step.",
        "operationId": "CreateStepNote",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "groupNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "x-order": 400
          },
          {
            "name": "stepNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "x-order": 400
          },
          {
            "name": "taskCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTaskItemNoteRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NoteDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/tasks/{taskCode}/groups/{groupNumber}/steps/{stepNumber}/notes/pinned": {
      "get": {
        "tags": [
          "Task - Workflow Notes"
        ],
        "summary": "Get Pinned Notes for Workflow Step",
        "description": "Gets all pinned notes for the specified workflow step (PinnedLevel > 0), ordered by PinnedLevel descending.",
        "operationId": "GetPinnedStepNotes",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "groupNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "x-order": 400
          },
          {
            "name": "stepNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "x-order": 400
          },
          {
            "name": "taskCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/NoteDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/tasks/{taskCode}/groups/{groupNumber}/steps/{stepNumber}/notes/{code}": {
      "get": {
        "tags": [
          "Task - Workflow Notes"
        ],
        "summary": "Get Note by Code",
        "description": "Gets a specific note for the workflow step by its code.",
        "operationId": "GetStepNote",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          },
          {
            "name": "groupNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "x-order": 400
          },
          {
            "name": "stepNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "x-order": 400
          },
          {
            "name": "taskCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NoteDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Task - Workflow Notes"
        ],
        "summary": "Update Note for Workflow Step",
        "description": "Updates an existing note for the specified workflow step.",
        "operationId": "UpdateStepNote",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          },
          {
            "name": "groupNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "x-order": 400
          },
          {
            "name": "stepNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "x-order": 400
          },
          {
            "name": "taskCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTaskItemNoteRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NoteDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Task - Workflow Notes"
        ],
        "summary": "Delete Note from Workflow Step",
        "description": "Deletes a note from the specified workflow step.",
        "operationId": "DeleteStepNote",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          },
          {
            "name": "groupNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "x-order": 400
          },
          {
            "name": "stepNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "x-order": 400
          },
          {
            "name": "taskCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/tasks/{taskCode}/workflow": {
      "post": {
        "tags": [
          "Task - Workflows"
        ],
        "summary": "Set Task Workflow",
        "description": "Initializes workflow step instances for a TaskItem based on a workflow template.\n            \nCreates progress tracking records for each step in the specified workflow:\n- Creates TaskItemWorkflowStep instances for all workflow steps\n- Sets initial assignments based on workflow template rules\n- Resets progress counters and status to starting values\n- Clears any existing workflow progress\n            \n**Warning: This operation clears all existing workflow progress.**\nAny completed steps will be lost and the workflow will restart from the beginning.\n            \nUse this endpoint to:\n- Assign a workflow to a task for the first time\n- Change the workflow assigned to a task\n- Reset workflow progress to start over\n- Set up workflow tracking for imported tasks\n            \nThe workflow template defines:\n- Which steps are created\n- Initial step assignments\n- Step dependencies and ordering\n- Default completion requirements\n            \nExample Request:\n{\n  \"workflowCode\": \"CLIENT-ONBOARDING\"\n}",
        "operationId": "InitializeWorkflowSteps",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "taskCode",
            "in": "path",
            "description": "The task code from the URL",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "requestBody": {
          "description": "The workflow initialization request",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InitializeWorkflowStepsRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WorkflowStepProgressDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "delete": {
        "tags": [
          "Task - Workflows"
        ],
        "summary": "Remove Task Workflow",
        "description": "Clears all workflow step progress for a TaskItem.\n            \nRemoves all workflow progress tracking:\n- Deletes all TaskItemWorkflowStep instances\n- Resets workflow progress counters to zero\n- Clears workflow reference from the task\n- Removes all step assignments and completion data\n            \nUse this endpoint to:\n- Remove workflow tracking from a task\n- Clear progress before assigning a different workflow\n- Reset workflow progress completely\n- Clean up workflow data for completed tasks\n            \n**Warning: This operation cannot be undone.**\nAll workflow progress data will be permanently lost.\n            \nAfter clearing, the task will have no workflow assigned\nand workflow progress fields will be reset to null/zero.",
        "operationId": "ClearWorkflowSteps",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "taskCode",
            "in": "path",
            "description": "The task code from the URL",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/tasks/{taskCode}/workflow/groups": {
      "get": {
        "tags": [
          "Task - Workflows"
        ],
        "summary": "Get Task Workflow Groups",
        "description": "Retrieves comprehensive workflow progress information for a TaskItem.\n            \nReturns detailed progress data including:\n- Overall completion statistics (total steps, completed steps, percentage)\n- All workflow steps with current status and assignments\n- Available steps that can be worked on next\n- Steps grouped by workflow groups for organized display\n            \nUse this endpoint to:\n- Display workflow progress dashboards\n- Show step-by-step task execution status\n- Identify bottlenecks and available work\n- Track overall workflow completion\n            \nExample Response:\n{\n  \"totalSteps\": 8,\n  \"completedSteps\": 3,\n  \"progressPercentage\": 37.5,\n  \"allSteps\": [...],\n  \"availableSteps\": [...],\n  \"groupedSteps\": [...]\n}",
        "operationId": "GetTaskWorkflowGroups",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "taskCode",
            "in": "path",
            "description": "The task code from the URL",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WorkflowGroupProgressDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/tasks/{taskCode}/workflow/groups/{groupNumber}/steps/{stepNumber}": {
      "get": {
        "tags": [
          "Task - Workflows"
        ],
        "summary": "Get Workflow Step",
        "description": "Retrieves a single workflow step with current status and execution details.\n            \nUse this endpoint to:\n- Check execution status after calling the Execute endpoint\n- Monitor SendEmail step progress (email sent status, message ID)\n- Query step details without loading all workflow groups\n- Poll for execution completion\n            \nFor SendEmail steps, the emailExecutionState property will be populated\nwhen the email has been sent, containing the emailMessageId and sentAt timestamp.",
        "operationId": "GetWorkflowStep",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "groupNumber",
            "in": "path",
            "description": "The group number (sort order) from the URL",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "x-order": 400
          },
          {
            "name": "stepNumber",
            "in": "path",
            "description": "The step number from the URL",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "x-order": 400
          },
          {
            "name": "taskCode",
            "in": "path",
            "description": "The task code from the URL",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowStepProgressDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "put": {
        "tags": [
          "Task - Workflows"
        ],
        "summary": "Update Workflow Step",
        "description": "Updates workflow step properties including status, assignment, and email configuration.\n            \nSupports updating:\n- Status changes (validates dependencies)\n- User assignment\n- Email configuration (SendEmail steps only, before execution)\n            \nEmail configuration uses PUT semantics - when provided, all fields must be included.\nConfiguration can only be updated on SendEmail steps that are not Completed status.\n            \nExample Request:\n{\n  \"status\": \"Completed\"\n}",
        "operationId": "UpdateWorkflowStep",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "groupNumber",
            "in": "path",
            "description": "The group number (sort order) from the URL",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "x-order": 400
          },
          {
            "name": "stepNumber",
            "in": "path",
            "description": "The step number to update from the URL",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "x-order": 400
          },
          {
            "name": "taskCode",
            "in": "path",
            "description": "The task code from the URL",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "requestBody": {
          "description": "The update request with new values",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateWorkflowStepRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowStepProgressDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/tasks/{taskCode}/workflow/groups/{groupNumber}/steps/{stepNumber}/execute": {
      "post": {
        "tags": [
          "Task - Workflows"
        ],
        "summary": "Execute Workflow Step",
        "description": "Queues a typed workflow step (e.g., SendEmail) for async execution.\n            \nValidation:\n- Step must exist and belong to the tenant\n- StepType must not be Standard (standard steps are manual checklist items)\n- Status must be NotStarted (prevents re-execution of already sent emails)\n- CanStart must be true (all dependency steps completed)\n            \nOn success, a WorkflowStepActionMessage is queued to the workflow-step-action queue\nfor processing by the function app. Returns 202 Accepted immediately.",
        "operationId": "ExecuteWorkflowStep",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "groupNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "x-order": 400
          },
          {
            "name": "stepNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "x-order": 400
          },
          {
            "name": "taskCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExecuteWorkflowStepRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/tasks/{taskCode}/workflow/groups/{groupNumber}/steps/{stepNumber}/send": {
      "post": {
        "tags": [
          "Task - Workflows"
        ],
        "summary": "Send Workflow Step Email",
        "description": "Sends a user-composed email for a SendEmail workflow step.\nThe email content comes from the request body, not the step's stored config.\nOn success, marks the step as Completed and records execution state.",
        "operationId": "SendWorkflowStepEmail",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "configCode",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "groupNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "x-order": 400
          },
          {
            "name": "stepNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "x-order": 400
          },
          {
            "name": "taskCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendMailboxEmailRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/tasks/{taskCode}/workflow/groups/{groupNumber}/steps/{stepNumber}/preview": {
      "get": {
        "tags": [
          "Task - Workflows"
        ],
        "summary": "Preview Workflow Step Email",
        "description": "Generates a preview of the email that would be sent by a SendEmail workflow step.\nRenders subject and body with resolved Liquid tokens and tenant branding,\nand resolves all To/CC recipients from contacts, users, and static addresses.\nDoes not send the email or change step status.",
        "operationId": "PreviewWorkflowStepEmail",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "groupNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "x-order": 400
          },
          {
            "name": "stepNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "x-order": 400
          },
          {
            "name": "taskCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowStepEmailPreviewDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/tasks/{taskCode}/workflow/groups/{groupNumber}/steps/{stepNumber}/client-data": {
      "get": {
        "tags": [
          "Task - Workflows"
        ],
        "summary": "Get Step Client Data",
        "description": "Returns the current client field values for the fields configured on an UpdateClientData workflow step, along with field metadata for rendering inputs.",
        "operationId": "GetWorkflowStepClientData",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "groupNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "x-order": 400
          },
          {
            "name": "stepNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "x-order": 400
          },
          {
            "name": "taskCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowStepClientDataDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "put": {
        "tags": [
          "Task - Workflows"
        ],
        "summary": "Save Step Client Data",
        "description": "Saves client data values from an UpdateClientData workflow step. Applies values to the client record. Set markComplete to true to also mark the step as Completed.",
        "operationId": "SaveWorkflowStepClientData",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "groupNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "x-order": 400
          },
          {
            "name": "stepNumber",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            },
            "x-order": 400
          },
          {
            "name": "taskCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SaveWorkflowStepClientDataRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/tasks": {
      "post": {
        "tags": [
          "Tasks"
        ],
        "summary": "Create TaskItem",
        "description": "Creates a new TaskItem for the specified tenant.",
        "operationId": "CreateTaskItem",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTaskItemRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskItemDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Tasks"
        ],
        "summary": "Bulk Delete TaskItems",
        "description": "Deletes multiple tasks at once. All tasks must exist.",
        "operationId": "BulkDeleteTasks",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkDeleteTasksRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkDeleteResult"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "patch": {
        "tags": [
          "Tasks"
        ],
        "summary": "Bulk Update TaskItems",
        "description": "Updates multiple tasks at once. Supports updating status and/or assigned user.\n\nAt least one of Status or AssignedUserCode must be provided.\n\n**Auto-assign behavior**: When setting status to InProgress without specifying an AssignedUserCode,\nany unassigned NotStarted tasks will be automatically assigned to the current user.",
        "operationId": "BulkUpdateTasks",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkUpdateTasksRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkUpdateResult"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "get": {
        "tags": [
          "Tasks"
        ],
        "summary": "List TaskItems",
        "description": "Lists TaskItems for the given tenant.\n\n**Date Range Options:**\n- Use dateRange for preset ranges (ThisWeek, ThisMonth, Today, etc.)\n- Use startDate/endDate for custom ranges\n- Date range is required when querying NotStarted tasks (or no status filter)\n- Date range is NOT required when filtering by non-NotStarted statuses only (e.g., InProgress, Completed)\n- Date range is NOT required when using isOverdue=true\n\n**Overdue Mode (isOverdue=true):**\n- Returns only tasks where DueDate < today\n- Automatically excludes Completed and Skipped statuses unless you specify a status filter\n- No date range required\n\n**Standard Mode (includeWorkflowSteps=false, default):**\n- Returns only tasks (materialised and optionally projected)\n- Use dateBasis to specify which date field to use for filtering: StartDate (default) or DueDate\n\n**Agenda Mode (includeWorkflowSteps=true):**\n- Returns both tasks AND workflow steps as TaskItemDto objects\n- Tasks: Returned with all standard TaskItem properties, WorkflowStepDetails = null\n- Workflow Steps: Returned with parent task properties populated, WorkflowStepDetails contains step-specific information\n\nSupports filtering by user(s), client(s), recurring task(s), category, date range, status, and isOverdue.",
        "operationId": "ListTaskItems",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "savedFilter",
            "in": "query",
            "description": "Code of a saved filter to apply. When provided, all filter parameters from the saved filter are used unless explicitly overridden by query parameters.",
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/TaskItemSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "client",
            "in": "query",
            "description": "Filter by client code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"CLI-001\", \"CLI-002\" ]"
            }
          },
          {
            "name": "user",
            "in": "query",
            "description": "Filter by user code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"USR-001\" ]"
            }
          },
          {
            "name": "recurringTask",
            "in": "query",
            "description": "Filter by recurring task code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"REC-001\", \"REC-002\" ]"
            }
          },
          {
            "name": "service",
            "in": "query",
            "description": "Filter by billable service code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"SRV-001\", \"SRV-002\" ]"
            }
          },
          {
            "name": "category",
            "in": "query",
            "description": "Filter by task category code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"CAT-001\", \"CAT-002\" ]"
            }
          },
          {
            "name": "team",
            "in": "query",
            "description": "Filter by team code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"payroll-team\" ]"
            }
          },
          {
            "name": "workflow",
            "in": "query",
            "description": "Filter by workflow code(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"WFL-001\", \"WFL-002\" ]"
            }
          },
          {
            "name": "stepType",
            "in": "query",
            "description": "Filter by workflow step type(s) - matches tasks with at least one step of these types",
            "schema": {
              "type": "array",
              "items": {
                "enum": [
                  "Standard",
                  "SendEmail",
                  "DocumentRequest",
                  "DocumentApproval",
                  "ClientConfirmation",
                  "SendDataForm",
                  "SetServiceStage",
                  "UpdateClientData",
                  "SetPipelineStage"
                ],
                "type": "string"
              },
              "example": "[ \"DocumentRequest\", \"ClientConfirmation\" ]"
            }
          },
          {
            "name": "currentStep",
            "in": "query",
            "description": "Filter by current workflow step name(s) - can specify multiple",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "example": "[ \"Prepare accounts\" ]"
            }
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter by task status(es)",
            "schema": {
              "type": "array",
              "items": {
                "enum": [
                  "NotStarted",
                  "InProgress",
                  "Blocked",
                  "Completed",
                  "Skipped"
                ],
                "type": "string"
              },
              "example": "[ \"InProgress\", \"Blocked\" ]"
            }
          },
          {
            "name": "includeWorkflowSteps",
            "in": "query",
            "description": "Include workflow steps in the results (default: false). When true, uses Agenda mode.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "dateRange",
            "in": "query",
            "description": "Preset date range. If CustomDateRange, startDate and endDate are required.",
            "schema": {
              "enum": [
                "ThisWeek",
                "NextWeek",
                "Last7Days",
                "Next7Days",
                "Last30Days",
                "Next30Days",
                "PreviousMonth",
                "ThisMonth",
                "NextMonth",
                "PreviousQuarter",
                "ThisQuarter",
                "NextQuarter",
                "PreviousYear",
                "ThisYear",
                "NextYear",
                "YearToDate",
                "PreviousFinancialYear",
                "ThisFinancialYear",
                "NextFinancialYear",
                "FinancialYearToDate",
                "Today",
                "CustomDateRange"
              ],
              "type": "string"
            }
          },
          {
            "name": "startDate",
            "in": "query",
            "description": "Filter tasks starting from this date. Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "description": "Filter tasks ending on this date. Only valid when dateRange=CustomDateRange",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "includeProjected",
            "in": "query",
            "description": "Include projected (virtual) tasks in the results (default: false)",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "dateBasis",
            "in": "query",
            "description": "Which date field to use as the basis for filtering: StartDate (default) or DueDate",
            "schema": {
              "enum": [
                "Any",
                "StartDate",
                "DueDate",
                "StatutoryDate",
                "CompletedDate"
              ],
              "type": "string"
            }
          },
          {
            "name": "isOverdue",
            "in": "query",
            "description": "Filter to only include overdue tasks (DueDate < today). No date range required when true.",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "isUnassigned",
            "in": "query",
            "description": "Include unassigned tasks. Can be combined with user filter to show unassigned OR assigned to specific users.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskItemDtoPagedResult"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/tasks/{code}": {
      "get": {
        "tags": [
          "Tasks"
        ],
        "summary": "Get TaskItem",
        "description": "Gets a TaskItem for the specified tenant.",
        "operationId": "GetTaskItem",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskItemDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Tasks"
        ],
        "summary": "Update TaskItem",
        "description": "Updates a TaskItem for the specified tenant.",
        "operationId": "UpdateTaskItem",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTaskItemRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskItemDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Tasks"
        ],
        "summary": "Delete TaskItem",
        "description": "Deletes a TaskItem for the specified tenant.",
        "operationId": "DeleteTaskItem",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/tasks/{code}/history": {
      "get": {
        "tags": [
          "Tasks"
        ],
        "summary": "Get TaskItem History",
        "description": "Returns the task's history timeline, newest first — every status and assignee\nchange on the task and its workflow steps, with who made each change.\nDerived from the temporal history of TaskItem and TaskItemWorkflowStep.",
        "operationId": "GetTaskItemHistory",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/TaskItemHistoryEventDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/task-categories": {
      "get": {
        "tags": [
          "Tasks - Categories"
        ],
        "summary": "List TaskCategories",
        "description": "Lists all TaskCategories for the given tenant.",
        "operationId": "ListTaskCategories",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/TaskCategorySortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search term to filter results",
            "schema": {
              "type": "string",
              "example": "keyword"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskCategoryDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Tasks - Categories"
        ],
        "summary": "Create TaskCategory",
        "description": "Creates a new TaskCategory for the specified tenant.",
        "operationId": "CreateTaskCategory",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTaskCategoryRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskCategoryDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/task-categories/{code}": {
      "get": {
        "tags": [
          "Tasks - Categories"
        ],
        "summary": "Get TaskCategory",
        "description": "Gets a TaskCategory for the specified tenant.",
        "operationId": "GetTaskCategory",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskCategoryDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Tasks - Categories"
        ],
        "summary": "Update TaskCategory",
        "description": "Updates a TaskCategory for the specified tenant.",
        "operationId": "UpdateTaskCategory",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTaskCategoryRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskCategoryDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Tasks - Categories"
        ],
        "summary": "Delete TaskCategory",
        "description": "Deletes a TaskCategory for the specified tenant.",
        "operationId": "DeleteTaskCategory",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/task-focus-config": {
      "get": {
        "tags": [
          "Tasks - Focus Config"
        ],
        "summary": "Get Task Focus Config",
        "description": "Gets the current user's task focus panel configuration. Auto-creates an empty default if none exists.",
        "operationId": "GetTaskFocusConfig",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskFocusConfigDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "put": {
        "tags": [
          "Tasks - Focus Config"
        ],
        "summary": "Upsert Task Focus Config",
        "description": "Creates or updates the current user's task focus panel configuration. Validates that all referenced saved task filters belong to the current user.",
        "operationId": "UpsertTaskFocusConfig",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTaskFocusConfigRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskFocusConfigDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/projected-tasks/{code}": {
      "get": {
        "tags": [
          "Tasks - Projected"
        ],
        "summary": "Get a single projected task item by composite code",
        "description": "Gets a projected (virtual) task item by its composite code. The code format is: proj-{recurringTaskCode}-{clientCode}-{yyyyMMdd}",
        "operationId": "GetProjectedTaskItem",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskItemDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/projected-tasks": {
      "post": {
        "tags": [
          "Tasks - Projected"
        ],
        "summary": "Materialise a projected task item into the database",
        "description": "Creates a real task item in the database from a projected (virtual) task item",
        "operationId": "MaterialiseProjectedTaskItem",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MaterialiseProjectedTaskRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskItemDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/projected-tasks/{code}/workflow/groups": {
      "get": {
        "tags": [
          "Tasks - Projected"
        ],
        "summary": "Get workflow groups and steps for a projected task with resolved assignments",
        "description": "Retrieves workflow groups and steps for a projected task with resolved assignments and calculated deadlines. No database writes are performed.",
        "operationId": "GetProjectedTaskWorkflowGroups",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WorkflowGroupProgressDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/recurring-tasks": {
      "get": {
        "tags": [
          "Tasks - Recurring"
        ],
        "summary": "List RecurringTaskItems",
        "description": "Lists all RecurringTaskItems for the given tenant.",
        "operationId": "ListRecurringTaskItems",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/RecurringTaskItemSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "isActive",
            "in": "query",
            "description": "Filter by active status (true = active only, false = inactive only)",
            "schema": {
              "type": "boolean",
              "example": "true"
            }
          },
          {
            "name": "serviceCode",
            "in": "query",
            "description": "Filter by billable service code",
            "schema": {
              "type": "string",
              "example": "ACC-001"
            }
          },
          {
            "name": "pipelineCode",
            "in": "query",
            "description": "Filter by sales pipeline code",
            "schema": {
              "type": "string",
              "example": "PIP-001"
            }
          },
          {
            "name": "clientCode",
            "in": "query",
            "description": "Filter by client code",
            "schema": {
              "type": "string",
              "example": "CLI-001"
            }
          },
          {
            "name": "categoryCode",
            "in": "query",
            "description": "Filter by task category code",
            "schema": {
              "type": "string",
              "example": "CAT-001"
            }
          },
          {
            "name": "workflowCode",
            "in": "query",
            "description": "Filter by workflow code",
            "schema": {
              "type": "string",
              "example": "WF-001"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search across recurring task code, name, and description (minimum 3 characters)",
            "schema": {
              "type": "string",
              "example": "vat"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecurringTaskItemDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Tasks - Recurring"
        ],
        "summary": "Create RecurringTaskItem",
        "description": "Creates a new RecurringTaskItem for the specified tenant.",
        "operationId": "CreateRecurringTaskItem",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateRecurringTaskItemRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecurringTaskItemDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/recurring-tasks/{code}": {
      "get": {
        "tags": [
          "Tasks - Recurring"
        ],
        "summary": "Get RecurringTaskItem",
        "description": "Gets a RecurringTaskItem for the specified tenant.",
        "operationId": "GetRecurringTaskItem",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecurringTaskItemDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Tasks - Recurring"
        ],
        "summary": "Update RecurringTaskItem",
        "description": "Updates a RecurringTaskItem for the specified tenant.",
        "operationId": "UpdateRecurringTaskItem",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateRecurringTaskItemRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecurringTaskItemDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Tasks - Recurring"
        ],
        "summary": "Delete RecurringTaskItem",
        "description": "Deletes a RecurringTaskItem for the specified tenant.",
        "operationId": "DeleteRecurringTaskItem",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/recurring-tasks/{code}/library-version": {
      "put": {
        "tags": [
          "Tasks - Recurring"
        ],
        "summary": "Revert RecurringTaskItem to Library",
        "description": "Reverts the RecurringTaskItem to the current library template version, overwriting any local edits. The RecurringTaskItem's code is preserved so it remains addressable at the same URL. Returns 400 if the RecurringTaskItem was not imported from the library, or 404 if the RecurringTaskItem or its source library template no longer exists.",
        "operationId": "RevertRecurringTaskItemToLibraryVersion",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecurringTaskItemDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/recurring-tasks/{code}/clients": {
      "get": {
        "tags": [
          "Tasks - Recurring"
        ],
        "summary": "Get Recurring Task Clients",
        "description": "Gets the list of clients associated with a specific recurring task.",
        "operationId": "GetRecurringTaskClients",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CodeAndNameDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "put": {
        "tags": [
          "Tasks - Recurring"
        ],
        "summary": "Update Recurring Task Clients",
        "description": "Updates the list of clients associated with a specific recurring task.",
        "operationId": "UpdateRecurringTaskClients",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/recurring-tasks/{code}/services": {
      "get": {
        "tags": [
          "Tasks - Recurring"
        ],
        "summary": "Get Recurring Task Services",
        "description": "Gets the list of billable services associated with a specific recurring task.",
        "operationId": "GetRecurringTaskServices",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CodeAndNameDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "put": {
        "tags": [
          "Tasks - Recurring"
        ],
        "summary": "Update Recurring Task Services",
        "description": "Updates the list of billable services associated with a specific recurring task.",
        "operationId": "UpdateRecurringTaskServices",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/recurring-tasks/{code}/pipelines": {
      "get": {
        "tags": [
          "Tasks - Recurring"
        ],
        "summary": "Get Recurring Task Pipelines",
        "description": "Gets the list of pipelines associated with a specific recurring task.",
        "operationId": "GetRecurringTaskPipelines",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CodeAndNameDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "put": {
        "tags": [
          "Tasks - Recurring"
        ],
        "summary": "Update Recurring Task Pipelines",
        "description": "Updates the list of pipelines associated with a specific recurring task.",
        "operationId": "UpdateRecurringTaskPipelines",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/saved-task-filters": {
      "get": {
        "tags": [
          "Tasks - Saved Filters"
        ],
        "summary": "List SavedTaskFilters",
        "description": "Lists the saved task filters visible to the current user within the tenant: their own filters plus any shared with the practice.",
        "operationId": "ListSavedTaskFilters",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/SavedTaskFilterSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "menuOnly",
            "in": "query",
            "description": "Filter to only show filters marked for menu display",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SavedTaskFilterDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "post": {
        "tags": [
          "Tasks - Saved Filters"
        ],
        "summary": "Create SavedTaskFilter",
        "description": "Creates a new saved task filter owned by the current user.",
        "operationId": "CreateSavedTaskFilter",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateSavedTaskFilterRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SavedTaskFilterDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/saved-task-filters/{code}": {
      "get": {
        "tags": [
          "Tasks - Saved Filters"
        ],
        "summary": "Get SavedTaskFilter",
        "description": "Gets a specific saved task filter by code. Only filters owned by or shared with the current user are accessible.",
        "operationId": "GetSavedTaskFilter",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SavedTaskFilterDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Tasks - Saved Filters"
        ],
        "summary": "Update SavedTaskFilter",
        "description": "Updates an existing saved task filter. Only the owner can update a filter.",
        "operationId": "UpdateSavedTaskFilter",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateSavedTaskFilterRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SavedTaskFilterDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Tasks - Saved Filters"
        ],
        "summary": "Delete SavedTaskFilter",
        "description": "Deletes a saved task filter. Only the owner can delete a filter.",
        "operationId": "DeleteSavedTaskFilter",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/saved-task-filters/{code}/menu": {
      "put": {
        "tags": [
          "Tasks - Saved Filters"
        ],
        "summary": "Set Menu Preference",
        "description": "Sets whether this saved task filter appears in the current user's menu. This is a per-user preference and does not affect other users.",
        "operationId": "SetSavedTaskFilterMenuPreference",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetSavedFilterMenuRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/teams/my": {
      "get": {
        "tags": [
          "Teams"
        ],
        "summary": "List My Teams",
        "description": "Returns all teams the current user is a member of.",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/TeamDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/teams": {
      "get": {
        "tags": [
          "Teams"
        ],
        "summary": "List Teams",
        "description": "Lists all Teams for the given tenant.",
        "operationId": "ListTeams",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/TeamSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search term to filter results",
            "schema": {
              "type": "string",
              "example": "keyword"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TeamDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Teams"
        ],
        "summary": "Create Team",
        "description": "Creates a new Team for the specified tenant.",
        "operationId": "CreateTeam",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTeamRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TeamDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/teams/{code}": {
      "get": {
        "tags": [
          "Teams"
        ],
        "summary": "Get Team",
        "description": "Gets a Team for the specified tenant.",
        "operationId": "GetTeam",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TeamDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Teams"
        ],
        "summary": "Update Team",
        "description": "Updates a Team for the specified tenant.",
        "operationId": "UpdateTeam",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTeamRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TeamDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Teams"
        ],
        "summary": "Delete Team",
        "description": "Deletes a Team for the specified tenant.",
        "operationId": "DeleteTeam",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/teams/{code}/members": {
      "get": {
        "tags": [
          "Teams"
        ],
        "summary": "List Team Members",
        "description": "Returns the members of a specific team.",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CodeAndNameDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Teams"
        ],
        "summary": "Add Team Members",
        "description": "Adds one or more users to a team.",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddTeamMembersRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CodeAndNameDto"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/teams/{code}/members/{userCode}": {
      "delete": {
        "tags": [
          "Teams"
        ],
        "summary": "Remove Team Member",
        "description": "Removes a user from a team.",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          },
          {
            "name": "userCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 212
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants": {
      "post": {
        "tags": [
          "Tenants"
        ],
        "summary": "Create Tenant",
        "description": "Creates a new tenant and assigns the current user as the admin for that tenant.",
        "operationId": "createTenant",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TenantCreateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          }
        }
      },
      "get": {
        "tags": [
          "Tenants"
        ],
        "summary": "List Tenants",
        "description": "Returns a list of all tenants that the authenticated user is a member of.",
        "operationId": "listTenants",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/TenantDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          }
        }
      }
    },
    "/tenants/{code}/me": {
      "get": {
        "tags": [
          "Tenants"
        ],
        "summary": "Get Role",
        "description": "Returns the current users role within the Tenant, including permissions.",
        "operationId": "getRoleInTenant",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantUserDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          }
        }
      }
    },
    "/tenants/{code}": {
      "get": {
        "tags": [
          "Tenants"
        ],
        "summary": "Get Tenant",
        "description": "Retrieves the details of a tenant using its Code identifier.",
        "operationId": "getTenantByCode",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Tenants"
        ],
        "summary": "Update Tenant",
        "description": "Updates the details of a tenant identified by its code.",
        "operationId": "updateTenantByCode",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TenantUpdateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/oauth/third-party/callback": {
      "get": {
        "tags": [
          "Third-Party Connections"
        ],
        "summary": "OAuth Callback",
        "description": "Handles OAuth redirect with authorization code to exchange for tokens",
        "operationId": "ThirdPartyOAuthRedirect",
        "parameters": [
          {
            "name": "code",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 2
          },
          {
            "name": "error",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "error_description",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "realmId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "state",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/tenants/{tenant}/connections": {
      "get": {
        "tags": [
          "Third-Party Connections"
        ],
        "summary": "List ThirdPartyConnections",
        "description": "Lists all ThirdPartyConnections for the given tenant.",
        "operationId": "ListThirdPartyConnections",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/ThirdPartyConnectionSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search term to filter results",
            "schema": {
              "type": "string",
              "example": "keyword"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ThirdPartyConnectionDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Third-Party Connections"
        ],
        "summary": "Create ThirdPartyConnection",
        "description": "Creates a new ThirdPartyConnection for the specified tenant.",
        "operationId": "CreateThirdPartyConnection",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateThirdPartyConnectionRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ThirdPartyConnectionDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/connections/{code}": {
      "get": {
        "tags": [
          "Third-Party Connections"
        ],
        "summary": "Get ThirdPartyConnection",
        "description": "Gets a ThirdPartyConnection for the specified tenant.",
        "operationId": "GetThirdPartyConnection",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ThirdPartyConnectionDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Third-Party Connections"
        ],
        "summary": "Update ThirdPartyConnection",
        "description": "Updates a ThirdPartyConnection for the specified tenant.",
        "operationId": "UpdateThirdPartyConnection",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateThirdPartyConnectionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ThirdPartyConnectionDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Third-Party Connections"
        ],
        "summary": "Delete ThirdPartyConnection",
        "description": "Deletes a ThirdPartyConnection for the specified tenant.",
        "operationId": "DeleteThirdPartyConnection",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/connections/{code}/set-organization": {
      "post": {
        "tags": [
          "Third-Party Connections"
        ],
        "summary": "Set Organization",
        "description": "If the ThirdPartyConnection has a status of \"Initialising\", then you need to use this endpoint to set the organization Id. The status will then become \"Active\"",
        "operationId": "SetOrganization",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetOrganizationRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/connections/{code}/base-folder": {
      "get": {
        "tags": [
          "Third-Party Connections"
        ],
        "summary": "Get Base Folder",
        "description": "Gets the base folder reference for a document storage connection, if one has been set.",
        "operationId": "getBaseFolder",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExternalFolderReferenceDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Third-Party Connections"
        ],
        "summary": "Set Base Folder",
        "description": "Creates or updates the base folder reference for a document storage connection. The connection must have the DocumentManagement capability.",
        "operationId": "upsertBaseFolder",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpsertBaseFolderRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExternalFolderReferenceDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/connections/{code}/auth-credentials": {
      "get": {
        "tags": [
          "Third-Party Connections"
        ],
        "summary": "Get Connection Credentials",
        "description": "Returns valid OAuth credentials for the connection, refreshing the token if expired. The connection must use OAuth authentication.",
        "operationId": "getConnectionCredentials",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConnectionCredentialsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/connections/{code}/storage-locations": {
      "get": {
        "tags": [
          "Third-Party Connections"
        ],
        "summary": "List Storage Locations",
        "description": "Lists storage locations (e.g. SharePoint sites and their document libraries) available through this connection. Uses cached data by default; pass `refresh=true` to re-query the platform API.",
        "operationId": "listConnectionStorageLocations",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          },
          {
            "name": "refresh",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/StorageLocationDto"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/connections/{code}/folders": {
      "get": {
        "tags": [
          "Third-Party Connections"
        ],
        "summary": "List Connection Folders",
        "description": "Lists subfolders for a document storage connection. Pass `parentFolderId` to drill into a specific folder; omit it to list the connection's root folders.",
        "operationId": "listConnectionFolders",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          },
          {
            "name": "driveId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 400
          },
          {
            "name": "parentFolderId",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ConnectionFolderDto"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/time-entries": {
      "get": {
        "tags": [
          "Time Tracking"
        ],
        "summary": "List TimeEntries",
        "description": "Lists all TimeEntries for the given tenant.",
        "operationId": "ListTimeEntries",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/TimeEntrySortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "userCode",
            "in": "query",
            "description": "Filter by team member code",
            "schema": {
              "type": "string",
              "example": "jsmith"
            }
          },
          {
            "name": "clientCode",
            "in": "query",
            "description": "Filter by linked client code",
            "schema": {
              "type": "string",
              "example": "acme-ltd"
            }
          },
          {
            "name": "taskItemCode",
            "in": "query",
            "description": "Filter by linked task code",
            "schema": {
              "type": "string",
              "example": "task-123"
            }
          },
          {
            "name": "dateRange",
            "in": "query",
            "description": "Preset date range for the entry window. When set (and not CustomDateRange), fromDate/toDate are calculated automatically.",
            "schema": {
              "enum": [
                "ThisWeek",
                "NextWeek",
                "Last7Days",
                "Next7Days",
                "Last30Days",
                "Next30Days",
                "PreviousMonth",
                "ThisMonth",
                "NextMonth",
                "PreviousQuarter",
                "ThisQuarter",
                "NextQuarter",
                "PreviousYear",
                "ThisYear",
                "NextYear",
                "YearToDate",
                "PreviousFinancialYear",
                "ThisFinancialYear",
                "NextFinancialYear",
                "FinancialYearToDate",
                "Today",
                "CustomDateRange"
              ],
              "type": "string"
            }
          },
          {
            "name": "fromDate",
            "in": "query",
            "description": "Only include entries on or after this date",
            "schema": {
              "type": "string",
              "example": "2026-01-01"
            }
          },
          {
            "name": "toDate",
            "in": "query",
            "description": "Only include entries on or before this date",
            "schema": {
              "type": "string",
              "example": "2026-01-31"
            }
          },
          {
            "name": "isBillable",
            "in": "query",
            "description": "Filter by whether the entry is billable",
            "schema": {
              "type": "boolean",
              "example": "true"
            }
          },
          {
            "name": "isBilled",
            "in": "query",
            "description": "Filter by whether the entry has been billed",
            "schema": {
              "type": "boolean",
              "example": "false"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search across description, client name and task name (minimum 3 characters)",
            "schema": {
              "type": "string",
              "example": "vat return"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimeEntryDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Time Tracking"
        ],
        "summary": "Create TimeEntry",
        "description": "Creates a new TimeEntry for the specified tenant.",
        "operationId": "CreateTimeEntry",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTimeEntryRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimeEntryDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/time-entries/{code}": {
      "get": {
        "tags": [
          "Time Tracking"
        ],
        "summary": "Get TimeEntry",
        "description": "Gets a TimeEntry for the specified tenant.",
        "operationId": "GetTimeEntry",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimeEntryDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Time Tracking"
        ],
        "summary": "Update TimeEntry",
        "description": "Updates a TimeEntry for the specified tenant.",
        "operationId": "UpdateTimeEntry",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTimeEntryRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimeEntryDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Time Tracking"
        ],
        "summary": "Delete TimeEntry",
        "description": "Deletes a TimeEntry for the specified tenant.",
        "operationId": "DeleteTimeEntry",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/time-entries/unbilled-clients": {
      "get": {
        "tags": [
          "Time Tracking"
        ],
        "summary": "List Unbilled Time Clients",
        "description": "Lists the clients that have unbilled billable time, with the unbilled minutes and entry count for each. Paged, ordered by client name; search filters on the client name.",
        "operationId": "GetUnbilledTimeClients",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 150
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 0,
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "default": 20,
              "example": "20"
            },
            "x-order": 501
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnbilledTimeClientDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/time-entries/bill": {
      "post": {
        "tags": [
          "Time Tracking"
        ],
        "summary": "Bill Time Entries",
        "description": "Converts unbilled billable time entries for a single client into billing line items, one per distinct hourly rate.",
        "operationId": "BillTimeEntries",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BillTimeEntriesRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ClientBillingLineItemDto"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/time-recording-settings": {
      "get": {
        "tags": [
          "Time Tracking - Settings"
        ],
        "summary": "Get time recording settings",
        "description": "Returns the time recording settings for the specified tenant",
        "operationId": "GetTimeTracking-Settings",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimeRecordingSettingsDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "put": {
        "tags": [
          "Time Tracking - Settings"
        ],
        "summary": "Update time recording settings",
        "description": "Updates the time recording settings for the specified tenant",
        "operationId": "UpdateTimeTracking-Settings",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTimeRecordingSettingsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimeRecordingSettingsDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/timer": {
      "get": {
        "tags": [
          "Time Tracking - Timer"
        ],
        "summary": "Get Running Timer",
        "description": "Returns the calling user's running timer, or null when no timer is running.",
        "operationId": "GetRunningTimer",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RunningTimerDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "put": {
        "tags": [
          "Time Tracking - Timer"
        ],
        "summary": "Start Running Timer",
        "description": "Starts a timer for the calling user, or updates the details of the one already running. The start time is preserved on update.",
        "operationId": "StartRunningTimer",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StartRunningTimerRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RunningTimerDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "delete": {
        "tags": [
          "Time Tracking - Timer"
        ],
        "summary": "Discard Running Timer",
        "description": "Discards the calling user's running timer without logging any time.",
        "operationId": "DiscardRunningTimer",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/timer/pause": {
      "post": {
        "tags": [
          "Time Tracking - Timer"
        ],
        "summary": "Pause Running Timer",
        "description": "Pauses the calling user's running timer — elapsed time stops accruing until it is resumed. Pausing an already-paused timer has no effect.",
        "operationId": "PauseRunningTimer",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RunningTimerDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/timer/resume": {
      "post": {
        "tags": [
          "Time Tracking - Timer"
        ],
        "summary": "Resume Running Timer",
        "description": "Resumes the calling user's paused timer. Resuming a timer that isn't paused has no effect.",
        "operationId": "ResumeRunningTimer",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RunningTimerDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/timers": {
      "get": {
        "tags": [
          "Time Tracking - Timer"
        ],
        "summary": "List Running Timers",
        "description": "Lists every running timer in the tenant, longest-running first — the admin view for spotting forgotten timers.",
        "operationId": "ListRunningTimers",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/RunningTimerDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/timers/{code}/pause": {
      "post": {
        "tags": [
          "Time Tracking - Timer"
        ],
        "summary": "Pause Running Timer By Code",
        "description": "Pauses any user's running timer — stops the clock on a forgotten timer without losing the accrued time. The owner can still resume or log it. Pausing an already-paused timer has no effect.",
        "operationId": "PauseRunningTimerByCode",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RunningTimerDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/timers/{code}": {
      "delete": {
        "tags": [
          "Time Tracking - Timer"
        ],
        "summary": "Discard Running Timer By Code",
        "description": "Discards any user's running timer without logging time — the admin cleanup action for forgotten timers.",
        "operationId": "DiscardRunningTimerByCode",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/account/profile": {
      "get": {
        "tags": [
          "User - Account"
        ],
        "summary": "Get current user's profile",
        "description": "Returns the profile information of the currently authenticated user including first name, last name, and avatar",
        "operationId": "GetUserProfile",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserProfileResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      },
      "put": {
        "tags": [
          "User - Account"
        ],
        "summary": "Update current user's profile",
        "description": "Updates the currently authenticated user's profile information (first name and last name only). To update the avatar, use the PUT /account/avatar endpoint.",
        "operationId": "UpdateUserProfile",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateUserProfileRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserProfileResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/account/avatar": {
      "put": {
        "tags": [
          "User - Account"
        ],
        "summary": "Set current user's avatar",
        "description": "Sets the currently authenticated user's avatar by uploading an image file. The image will be validated, processed (EXIF stripped), uploaded to blob storage, and the URL stored in the user profile. Maximum file size: 5MB. Allowed formats: PNG, JPEG, WEBP.",
        "operationId": "SetUserAvatar",
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "required": [
                  "file"
                ],
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              },
              "encoding": {
                "file": {
                  "style": "form"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserProfileResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      },
      "delete": {
        "tags": [
          "User - Account"
        ],
        "summary": "Remove current user's avatar",
        "description": "Removes the currently authenticated user's avatar",
        "operationId": "RemoveUserAvatar",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserProfileResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/account/utm": {
      "post": {
        "tags": [
          "User - Account"
        ],
        "summary": "Set UTM Info (write-once)",
        "description": "Sets the currently authenticated user's UTM tracking information. This is a write-once operation - if the user already has any UTM data, the request is silently ignored and returns 204 No Content. Returns 201 Created if UTM data was successfully stored.",
        "operationId": "SetUtmInfo",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UtmInfoDto"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created"
          },
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized"
          }
        }
      }
    },
    "/users/invite-codes": {
      "get": {
        "tags": [
          "User - Account"
        ],
        "summary": "Get Invite Codes",
        "description": "Gets all invite codes for the authenticated user.",
        "operationId": "GetInviteCodes",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/InviteCodeDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/user-invitations": {
      "get": {
        "tags": [
          "User - Invitations"
        ],
        "summary": "List Pending Invitations",
        "description": "Returns:\n- 200 OK with list of pending invitations (empty list if none)\n- 400 Bad Request if email is not verified\n- 401 Unauthorized if not authenticated",
        "operationId": "GetInvitations",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/InvitationDetailsResponse"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "put": {
        "tags": [
          "User - Invitations"
        ],
        "summary": "Process Invitation",
        "description": "Responds to the user's invitation to join the tenant.\n            \nReturns:\n- 200 OK with response details\n- 400 Bad Request if token invalid or email mismatch\n- 401 Unauthorized if not authenticated",
        "operationId": "ProcessInvitation",
        "requestBody": {
          "description": "The invitation response request",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProcessInvitationRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProcessInvitationResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "User - Invitations"
        ],
        "summary": "Send Invitation",
        "description": "Sends an invitation email to a user to join a tenant.\n            \nReturns:\n- 200 OK if invitation was sent\n- 400 Bad Request if user already accepted or invalid request\n- 401 Unauthorized if not authenticated\n- 404 Not Found if user doesn't exist in tenant",
        "operationId": "SendInvitation",
        "requestBody": {
          "description": "The send invitation request",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendInvitationRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/user-view-preferences/{viewKey}": {
      "get": {
        "tags": [
          "User View Preferences"
        ],
        "summary": "Get User View Preference",
        "description": "Gets the current user's view preference for a specific view key. Auto-creates an empty default if none exists.",
        "operationId": "GetUserViewPreference",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "viewKey",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserViewPreferenceDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "put": {
        "tags": [
          "User View Preferences"
        ],
        "summary": "Upsert User View Preference",
        "description": "Creates or updates the current user's view preference for a specific view key.",
        "operationId": "UpsertUserViewPreference",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "viewKey",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpsertUserViewPreferenceRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserViewPreferenceDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/users/me": {
      "get": {
        "tags": [
          "Users"
        ],
        "summary": "Get current authenticated user",
        "description": "Returns the profile information of the currently authenticated user",
        "operationId": "GetCurrentUser",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CurrentUserResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/users/email-verification": {
      "put": {
        "tags": [
          "Users"
        ],
        "summary": "Verify user's email address",
        "description": "Verifies a user's email address using the verification key from the email link. Returns 200 if email is successfully verified (idempotent - also returns 200 if already verified). Returns 404 if the verification token is invalid or not found. Returns 410 if the token has expired - a new verification email is automatically sent in this case. Returns 400 for malformed requests (invalid GUID format, missing required fields).",
        "operationId": "VerifyEmail",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VerifyEmailRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VerificationResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VerificationResponse"
                }
              }
            }
          },
          "410": {
            "description": "Gone",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VerificationResponse"
                }
              }
            }
          }
        }
      }
    },
    "/users/email-verifications": {
      "post": {
        "tags": [
          "Users"
        ],
        "summary": "Resend email verification link",
        "description": "Resends a verification email to the authenticated user's email address.",
        "operationId": "ResendVerificationEmail",
        "responses": {
          "202": {
            "description": "Accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResendVerificationResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/users": {
      "get": {
        "tags": [
          "Users"
        ],
        "summary": "List TenantUsers",
        "description": "Lists all TenantUsers for the given tenant.",
        "operationId": "ListTenantUsers",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/TenantUserSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter by user status (Created, Invited, Active, Disabled, Declined)",
            "schema": {
              "enum": [
                "Created",
                "Invited",
                "Active",
                "Disabled",
                "Declined",
                "Deleted"
              ],
              "type": "string",
              "example": "Active"
            }
          },
          {
            "name": "systemRole",
            "in": "query",
            "description": "Filter by system role (Admin, StandardUser, Viewer)",
            "schema": {
              "enum": [
                "Admin",
                "StandardUser",
                "Viewer"
              ],
              "type": "string",
              "example": "StandardUser"
            }
          },
          {
            "name": "isClientManager",
            "in": "query",
            "description": "Filter by client manager status (true = managers only, false = non-managers only)",
            "schema": {
              "type": "boolean",
              "example": "true"
            }
          },
          {
            "name": "isPartner",
            "in": "query",
            "description": "Filter by partner status (true = partners only, false = non-partners only)",
            "schema": {
              "type": "boolean",
              "example": "true"
            }
          },
          {
            "name": "isAssociate",
            "in": "query",
            "description": "Filter by associate status (true = associates only, false = non-associates only)",
            "schema": {
              "type": "boolean",
              "example": "true"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search across user code, first name, last name, and email (minimum 3 characters)",
            "schema": {
              "type": "string",
              "example": "john"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantUserDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Users"
        ],
        "summary": "Create TenantUser",
        "description": "Creates a new TenantUser for the specified tenant.",
        "operationId": "CreateTenantUser",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTenantUserRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantUserDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/users/{code}": {
      "get": {
        "tags": [
          "Users"
        ],
        "summary": "Get TenantUser",
        "description": "Gets a TenantUser for the specified tenant.",
        "operationId": "GetTenantUser",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantUserDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Users"
        ],
        "summary": "Update TenantUser",
        "description": "Updates a TenantUser for the specified tenant.",
        "operationId": "UpdateTenantUser",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTenantUserRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TenantUserDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Users"
        ],
        "summary": "Delete TenantUser",
        "description": "Deletes a TenantUser for the specified tenant.",
        "operationId": "DeleteTenantUser",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      },
      "patch": {
        "tags": [
          "Users"
        ],
        "summary": "Patch User",
        "description": "Applies a partial update to a user. Currently patches the time tracking hourly rate (null clears it so the practice default applies).",
        "operationId": "PatchTenantUser",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchTenantUserRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/workflows": {
      "get": {
        "tags": [
          "Workflows"
        ],
        "summary": "List Workflows",
        "description": "Lists all Workflows for the given tenant.",
        "operationId": "ListWorkflows",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "offset",
            "in": "query",
            "description": "Number of records to skip (default: 0). Use with limit for pagination.",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "0"
            },
            "x-order": 500
          },
          {
            "name": "limit",
            "in": "query",
            "description": "Maximum number of records to return (default: 10, max: 50)",
            "schema": {
              "type": "integer",
              "format": "int32",
              "example": "20"
            },
            "x-order": 501
          },
          {
            "name": "sortBy",
            "in": "query",
            "description": "Field to sort by.",
            "schema": {
              "$ref": "#/components/schemas/WorkflowSortField"
            },
            "x-order": 502
          },
          {
            "name": "sortDesc",
            "in": "query",
            "description": "Sort in descending order (true) or ascending order (false, default)",
            "schema": {
              "type": "boolean",
              "example": "false"
            },
            "x-order": 503
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search term to filter results",
            "schema": {
              "type": "string",
              "example": "keyword"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowDtoPagedResult"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "post": {
        "tags": [
          "Workflows"
        ],
        "summary": "Create Workflow",
        "description": "Creates a new Workflow for the specified tenant.",
        "operationId": "CreateWorkflow",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateWorkflowRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "403": {
            "description": "Forbidden"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/workflows/{code}": {
      "get": {
        "tags": [
          "Workflows"
        ],
        "summary": "Get Workflow",
        "description": "Gets a Workflow for the specified tenant.",
        "operationId": "GetWorkflow",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "put": {
        "tags": [
          "Workflows"
        ],
        "summary": "Update Workflow",
        "description": "Updates a Workflow for the specified tenant.",
        "operationId": "UpdateWorkflow",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateWorkflowRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      },
      "delete": {
        "tags": [
          "Workflows"
        ],
        "summary": "Delete Workflow",
        "description": "Deletes a Workflow for the specified tenant.",
        "operationId": "DeleteWorkflow",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "204": {
            "description": "No Content"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          },
          "409": {
            "description": "Conflict"
          }
        }
      }
    },
    "/tenants/{tenant}/workflows/library": {
      "get": {
        "tags": [
          "Workflows"
        ],
        "summary": "List Library Workflows",
        "description": "List all Workflows available in the library as templates. Use optional 'search' query parameter to filter by Code, Name, or Description.",
        "operationId": "ListLibraryWorkflows",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "x-order": 150
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WorkflowDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/workflows/library/{code}": {
      "get": {
        "tags": [
          "Workflows"
        ],
        "summary": "Get Library Workflow",
        "description": "Get details of a specific Workflow template from the library",
        "operationId": "GetLibraryWorkflow",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/workflows/{code}/library-version": {
      "put": {
        "tags": [
          "Workflows"
        ],
        "summary": "Revert Workflow to Library",
        "description": "Reverts the Workflow to the current library template version, overwriting any local edits. The Workflow's code is preserved so it remains addressable at the same URL. Returns 400 if the Workflow was not imported from the library, or 404 if the Workflow or its source library template no longer exists.",
        "operationId": "RevertWorkflowToLibraryVersion",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 2
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/workflows/library/{libraryCode}/import": {
      "post": {
        "tags": [
          "Workflows"
        ],
        "summary": "Import from Library",
        "description": "Imports a workflow from the library, creating a new tenant copy each call. Re-imports of the same library item are supported and produce a fresh row with the supplied NameSuffix appended (or auto '(N)' when omitted).",
        "operationId": "ImportWorkflowFromLibrary",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "libraryCode",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 400
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImportFromLibraryRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/workflows/generate": {
      "post": {
        "tags": [
          "Workflows"
        ],
        "summary": "Generate Workflow",
        "description": "Generates a complete Workflow DTO with AI-generated groups and steps based on the workflow name and description",
        "operationId": "GenerateWorkflow",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateWorkflowRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    },
    "/tenants/{tenant}/working-days": {
      "get": {
        "tags": [
          "Working Days"
        ],
        "summary": "Get Working Days Settings",
        "description": "Returns the working days configuration including bank holiday region and default holiday adjustment behavior for task scheduling",
        "operationId": "GetWorkingDays",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkingDaySettingsDto"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      },
      "put": {
        "tags": [
          "Working Days"
        ],
        "summary": "Update Working Days Settings",
        "description": "Updates the working days configuration for the tenant",
        "operationId": "UpdateWorkingDays",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateWorkingDaySettingsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkingDaySettingsDto"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          },
          "404": {
            "description": "Not Found"
          }
        }
      }
    },
    "/tenants/{tenant}/bank-holidays": {
      "get": {
        "tags": [
          "Working Days"
        ],
        "summary": "List Bank Holidays",
        "description": "Returns bank holidays for the tenant's configured region. Filter by year (defaults to current year) and search by name.",
        "operationId": "ListBankHolidays",
        "parameters": [
          {
            "name": "tenant",
            "in": "path",
            "description": "The Tenant.Code",
            "required": true,
            "schema": {
              "type": "string"
            },
            "x-order": 0
          },
          {
            "name": "year",
            "in": "query",
            "description": "Filter by year. Defaults to current year if not specified.",
            "schema": {
              "type": "integer",
              "example": "2025"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search by holiday name (minimum 3 characters)",
            "schema": {
              "type": "string",
              "example": "christmas"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/BankHolidayDto"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized – Invalid or missing API key"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "AcceptEngagementRequest": {
        "required": [
          "acceptedByName",
          "contactPreferences",
          "signature"
        ],
        "type": "object",
        "properties": {
          "signature": {
            "minLength": 1,
            "type": "string",
            "description": "Base64-encoded signature image"
          },
          "contactPreferences": {
            "$ref": "#/components/schemas/ContactPreferencesDto"
          },
          "acceptedByName": {
            "maxLength": 200,
            "minLength": 1,
            "type": "string",
            "description": "Name as typed by the signee at acceptance time"
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for accepting an engagement"
      },
      "AcceptanceDto": {
        "type": "object",
        "properties": {
          "acceptedDate": {
            "type": "string",
            "description": "Date and time when the engagement was accepted",
            "format": "date-time",
            "nullable": true
          },
          "acceptedIpAddress": {
            "type": "string",
            "description": "IP address from which the engagement was accepted (for audit purposes)",
            "nullable": true
          },
          "acceptanceSignature": {
            "type": "string",
            "description": "Digital signature data from the acceptance (base64 encoded image)",
            "nullable": true
          },
          "acceptedByName": {
            "type": "string",
            "description": "Name as typed by the signee at acceptance time",
            "nullable": true
          },
          "acceptedUserAgent": {
            "type": "string",
            "description": "Browser user agent string captured at acceptance time",
            "nullable": true
          },
          "manuallyAccepted": {
            "type": "boolean",
            "description": "Indicates whether the engagement was manually accepted (true) or accepted via the online acceptance page (false)"
          },
          "acceptanceSignatureImage": {
            "type": "string",
            "description": "Digital signature as an HTML img tag for template rendering.\nConverts the base64-encoded signature to an img element with data URI.",
            "nullable": true,
            "readOnly": true
          }
        },
        "additionalProperties": false,
        "description": "Acceptance information for an engagement"
      },
      "ActivateServicesResponse": {
        "type": "object",
        "properties": {
          "activatedCount": {
            "type": "integer",
            "description": "Number of services activated",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Response from activating proposed services"
      },
      "AddAmlContactRequest": {
        "required": [
          "clientCode",
          "clientContactCode"
        ],
        "type": "object",
        "properties": {
          "clientCode": {
            "minLength": 1,
            "type": "string",
            "description": "The Sodium client code that owns this contact relationship."
          },
          "clientContactCode": {
            "minLength": 1,
            "type": "string",
            "description": "The Sodium client-contact code (same as the contact's code) identifying which contact to push."
          }
        },
        "additionalProperties": false,
        "description": "Request to push a Sodium contact to the AML platform.\nThe API looks up all contact fields server-side from the client-contact relationship."
      },
      "AddTeamMembersRequest": {
        "required": [
          "userCodes"
        ],
        "type": "object",
        "properties": {
          "userCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The user codes of the members to add"
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for adding members to a team"
      },
      "AgentAuthorisationStatus": {
        "enum": [
          "NotRequested",
          "Requested",
          "Granted"
        ],
        "type": "string"
      },
      "AgentAuthorisationType": {
        "enum": [
          "SelfAssessment",
          "CorporationTax",
          "PayeForEmployers",
          "IndividualPayAsYouEarn",
          "VAT",
          "ConstructionIndustryScheme",
          "TaxCredits",
          "HighIncomeChildBenefitCharge",
          "MakingTaxDigitalIncomeTax",
          "MakingTaxDigitalVat",
          "Trusts"
        ],
        "type": "string"
      },
      "AiActivity": {
        "enum": [
          "ServiceGen",
          "ProposalContentGen",
          "ServiceScheduleGen",
          "DescriptionGen",
          "PricingFactorsGen",
          "PricingFactorOptionsGen",
          "WorkflowGen"
        ],
        "type": "string"
      },
      "AiContext": {
        "enum": [
          "AccountancyPractice",
          "BookkeepingPractice"
        ],
        "type": "string"
      },
      "AiGenerationRequest": {
        "required": [
          "activity",
          "input"
        ],
        "type": "object",
        "properties": {
          "activity": {
            "$ref": "#/components/schemas/AiActivity"
          },
          "input": {
            "minLength": 1,
            "type": "string",
            "description": "The input text or context for the AI generation"
          },
          "code": {
            "type": "string",
            "description": "Optional code of the related entity (e.g., service code, client code)",
            "nullable": true
          },
          "useCache": {
            "type": "boolean",
            "description": "Whether to use cached AI responses if available (default: true)"
          }
        },
        "additionalProperties": false,
        "description": "Request to generate content using AI based on the specified activity"
      },
      "AiSettingsDto": {
        "type": "object",
        "properties": {
          "useCustomKey": {
            "type": "boolean",
            "description": "Whether to use a custom OpenAI API key instead of the shared platform key"
          },
          "customKey": {
            "type": "string",
            "description": "The custom OpenAI API key (only used if UseCustomKey is true)",
            "nullable": true
          },
          "model": {
            "type": "string",
            "description": "The AI model identifier to use (e.g., \"gpt-4\", \"gpt-3.5-turbo\", or \"default\" for platform default)",
            "nullable": true
          },
          "useBritishEnglish": {
            "type": "boolean",
            "description": "Whether to use British English spelling and conventions in AI-generated content"
          },
          "context": {
            "$ref": "#/components/schemas/AiContext"
          },
          "modelServicesScheduleContent": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "modelProposalsContent": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          }
        },
        "additionalProperties": false,
        "description": "Configuration for AI/LLM integration settings at the tenant level.\nControls which AI model to use and whether to use a custom API key or the shared platform key.\nIncludes references to content blocks that provide context for AI-generated content in proposals and service schedules."
      },
      "AiUsageSummaryDto": {
        "type": "object",
        "properties": {
          "userSharedKeyTokens": {
            "type": "integer",
            "description": "Total tokens used by the current user with the shared API key",
            "format": "int32"
          },
          "userCustomKeyTokens": {
            "type": "integer",
            "description": "Total tokens used by the current user with their custom API key",
            "format": "int32"
          },
          "tenantSharedKeyTokens": {
            "type": "integer",
            "description": "Total tokens used by all users in the tenant with the shared API key",
            "format": "int32"
          },
          "tenantCustomKeyTokens": {
            "type": "integer",
            "description": "Total tokens used by all users in the tenant with their custom API keys",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Summary of AI usage tokens for a specific date range"
      },
      "AmlClientDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "isIndividual": {
            "type": "boolean"
          },
          "regNumber": {
            "type": "string",
            "nullable": true
          },
          "contacts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AmlContactDto"
            },
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/AmlStatus"
          },
          "riskLevel": {
            "$ref": "#/components/schemas/AmlRiskLevel"
          },
          "externalUrl": {
            "type": "string",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "AmlClientDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AmlClientDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "AmlClientSortField": {
        "enum": [
          "Name"
        ],
        "type": "string"
      },
      "AmlContactDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "nullable": true
          },
          "firstName": {
            "type": "string",
            "nullable": true
          },
          "middleName": {
            "type": "string",
            "nullable": true
          },
          "lastName": {
            "type": "string",
            "nullable": true
          },
          "email": {
            "type": "string",
            "nullable": true
          },
          "phone": {
            "type": "string",
            "nullable": true
          },
          "dateOfBirth": {
            "type": "string",
            "nullable": true
          },
          "address": {
            "type": "string",
            "nullable": true
          },
          "companiesHousePersonalCode": {
            "type": "string",
            "nullable": true
          },
          "externalUrl": {
            "type": "string",
            "nullable": true
          },
          "onboardingStatus": {
            "$ref": "#/components/schemas/AmlContactStatus"
          },
          "amlStatus": {
            "$ref": "#/components/schemas/AmlContactStatus"
          }
        },
        "additionalProperties": false,
        "description": "Contact details from the AML platform."
      },
      "AmlContactStatus": {
        "enum": [
          "NotStarted",
          "InProgress",
          "Ready",
          "InReview",
          "Complete",
          "ActionRequired",
          "Cancelled"
        ],
        "type": "string"
      },
      "AmlMailTemplateDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "isDefault": {
            "type": "boolean"
          }
        },
        "additionalProperties": false,
        "description": "A mail template configured in the AML platform."
      },
      "AmlOnboardingLevelDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "isDefault": {
            "type": "boolean"
          }
        },
        "additionalProperties": false,
        "description": "An onboarding level configured in the AML platform."
      },
      "AmlOnboardingUrlResponse": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "description": "The onboarding URL. Null if no onboarding report exists or the URL is no longer available.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response containing the onboarding URL for a contact."
      },
      "AmlRiskAssessmentDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/AmlRiskAssessmentStatus"
          },
          "riskLevel": {
            "$ref": "#/components/schemas/AmlRiskLevel"
          },
          "completedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "notes": {
            "type": "string",
            "nullable": true
          },
          "reviewNotes": {
            "type": "string",
            "nullable": true
          },
          "preparedBy": {
            "type": "string",
            "nullable": true
          },
          "reviewedBy": {
            "type": "string",
            "nullable": true
          },
          "externalUrl": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "AmlRiskAssessmentDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AmlRiskAssessmentDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "AmlRiskAssessmentStatus": {
        "enum": [
          "InProgress",
          "InReview",
          "Completed"
        ],
        "type": "string"
      },
      "AmlRiskLevel": {
        "enum": [
          "Low",
          "Normal",
          "High"
        ],
        "type": "string"
      },
      "AmlStatus": {
        "enum": [
          "Active",
          "Pending",
          "Archived"
        ],
        "type": "string"
      },
      "ApiKeyDto": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string",
            "description": "The unique identifier for this API key (use this for authentication via x-api-key header)",
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "description": "The friendly name for this API key",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "The date this API key was created",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "Represents an API key for authentication"
      },
      "ApplyServicePackageRequest": {
        "type": "object",
        "properties": {
          "status": {
            "$ref": "#/components/schemas/ServiceStatus"
          },
          "startDate": {
            "type": "string",
            "description": "The start date for the services. Defaults to today if not provided.",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for applying a service package to a client"
      },
      "AssignmentType": {
        "enum": [
          "Unassigned",
          "SpecificUser",
          "ClientManager",
          "ClientServiceManager",
          "ClientPartner",
          "ClientAssociate"
        ],
        "type": "string"
      },
      "AuditUserType": {
        "enum": [
          "System",
          "User",
          "Portal",
          "MagicLink"
        ],
        "type": "string"
      },
      "AuthenticationType": {
        "enum": [
          "OAuth",
          "ApiKey",
          "Basic",
          "OAuthClientCredentials"
        ],
        "type": "string"
      },
      "AvailableClientDto": {
        "type": "object",
        "properties": {
          "externalId": {
            "type": "string",
            "description": "Platform-specific customer identifier (used to perform the import)",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Customer/company name from the accounting platform",
            "nullable": true
          },
          "code": {
            "type": "string",
            "description": "Customer code/reference from the accounting platform (if available)",
            "nullable": true
          },
          "email": {
            "type": "string",
            "description": "Primary email address",
            "nullable": true
          },
          "phone": {
            "type": "string",
            "description": "Primary phone number",
            "nullable": true
          },
          "address": {
            "type": "string",
            "description": "Street address",
            "nullable": true
          },
          "city": {
            "type": "string",
            "description": "City/town",
            "nullable": true
          },
          "postalCode": {
            "type": "string",
            "description": "Postal/ZIP code",
            "nullable": true
          },
          "country": {
            "type": "string",
            "description": "Country",
            "nullable": true
          },
          "isActive": {
            "type": "boolean",
            "description": "Whether the customer is active in the accounting platform"
          },
          "contactCount": {
            "type": "integer",
            "description": "Number of contacts associated with this customer in the accounting platform",
            "format": "int32"
          },
          "importedAs": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          }
        },
        "additionalProperties": false,
        "description": "A customer/client retrieved from a third-party accounting platform (Xero, QuickBooks, FreeAgent, etc.)\nthat is available to be imported into Sodium as a client.\nShows the platform's data and indicates whether it has already been imported."
      },
      "AvailableClientDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AvailableClientDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "BackgroundImageDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique code for this background image.",
            "nullable": true
          },
          "imageAsset": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "pageSelection": {
            "$ref": "#/components/schemas/PageSelection"
          },
          "position": {
            "$ref": "#/components/schemas/BackgroundImagePosition"
          },
          "offsetXMm": {
            "type": "number",
            "description": "Horizontal offset in mm from the left edge. Only used when Position is Custom.",
            "format": "float"
          },
          "offsetYMm": {
            "type": "number",
            "description": "Vertical offset in mm from the top edge. Only used when Position is Custom.",
            "format": "float"
          },
          "widthMm": {
            "type": "number",
            "description": "Width in millimeters. Null means natural width or full page for FullPage position.",
            "format": "float",
            "nullable": true
          },
          "heightMm": {
            "type": "number",
            "description": "Height in millimeters. Null means natural height or full page for FullPage position.",
            "format": "float",
            "nullable": true
          },
          "opacity": {
            "type": "number",
            "description": "Opacity from 0.0 (transparent) to 1.0 (opaque). Useful for watermark effects.",
            "format": "float"
          },
          "overlayColor": {
            "type": "string",
            "description": "Optional overlay color in hex format. Applied with mix-blend-mode: multiply for a tint effect.",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "Rendering order (z-index). Lower values render behind higher values.",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "A background image configured on a design theme for PDF rendering."
      },
      "BackgroundImagePosition": {
        "enum": [
          "FullPage",
          "TopCenter",
          "BottomCenter",
          "Center",
          "TopLeft",
          "TopRight",
          "BottomLeft",
          "BottomRight",
          "Custom"
        ],
        "type": "string"
      },
      "BackgroundImageRequest": {
        "required": [
          "imageAssetCode"
        ],
        "type": "object",
        "properties": {
          "imageAssetCode": {
            "minLength": 1,
            "type": "string",
            "description": "Code of the image asset from the media library."
          },
          "pageSelection": {
            "$ref": "#/components/schemas/PageSelection"
          },
          "position": {
            "$ref": "#/components/schemas/BackgroundImagePosition"
          },
          "offsetXMm": {
            "maximum": 297,
            "minimum": 0,
            "type": "number",
            "description": "Horizontal offset in mm from the left edge. Only used when Position is Custom.",
            "format": "float"
          },
          "offsetYMm": {
            "maximum": 420,
            "minimum": 0,
            "type": "number",
            "description": "Vertical offset in mm from the top edge. Only used when Position is Custom.",
            "format": "float"
          },
          "widthMm": {
            "maximum": 297,
            "minimum": 1,
            "type": "number",
            "description": "Width in millimeters. Null means natural width or full page for FullPage position.",
            "format": "float",
            "nullable": true
          },
          "heightMm": {
            "maximum": 420,
            "minimum": 1,
            "type": "number",
            "description": "Height in millimeters. Null means natural height or full page for FullPage position.",
            "format": "float",
            "nullable": true
          },
          "opacity": {
            "maximum": 1,
            "minimum": 0,
            "type": "number",
            "description": "Opacity from 0.0 (transparent) to 1.0 (opaque). Useful for watermark effects.",
            "format": "float"
          },
          "overlayColor": {
            "maxLength": 10,
            "type": "string",
            "description": "Optional overlay color in hex format. Applied with mix-blend-mode: multiply for a tint effect.",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "Rendering order (z-index). Lower values render behind higher values.",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for creating or updating a background image on a design theme."
      },
      "BankHolidayDto": {
        "type": "object",
        "properties": {
          "date": {
            "type": "string",
            "description": "The date of the bank holiday",
            "format": "date"
          },
          "name": {
            "type": "string",
            "description": "Name of the bank holiday (e.g., \"Good Friday\", \"Christmas Day\")",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Bank holiday information"
      },
      "BankHolidayRegion": {
        "enum": [
          "None",
          "England",
          "Wales",
          "Scotland",
          "NorthernIreland"
        ],
        "type": "string"
      },
      "BillTimeEntriesRequest": {
        "required": [
          "timeEntryCodes"
        ],
        "type": "object",
        "properties": {
          "timeEntryCodes": {
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The codes of the time entries to bill"
          },
          "vatRate": {
            "$ref": "#/components/schemas/VatRate"
          },
          "description": {
            "maxLength": 500,
            "type": "string",
            "description": "The invoice line description. Defaults to a summary of the billed period when omitted.",
            "nullable": true
          },
          "billingDate": {
            "type": "string",
            "description": "Target invoice date. Defaults to today when omitted.",
            "format": "date-time",
            "nullable": true
          },
          "accountingCode": {
            "maxLength": 20,
            "type": "string",
            "description": "Accounting/nominal code. Defaults from the client billing settings when omitted.",
            "nullable": true
          },
          "lineMode": {
            "$ref": "#/components/schemas/TimeBillingLineMode"
          }
        },
        "additionalProperties": false,
        "description": "Request to convert unbilled billable time entries into client billing line items.\nAll entries must belong to the same client, be billable, unbilled, and carry an hourly rate.\nLine items are shaped by the line mode: combined (one per distinct hourly rate) or one per entry."
      },
      "BillableServiceDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Stable identifier. For library-shipped items this is the library code; for tenant-imported\nitems this is the tenant entity's own code.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name shown to users in lists, dialogs, and the import browser.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Optional human-readable summary of what this entity is for.",
            "nullable": true
          },
          "libraryCode": {
            "type": "string",
            "description": "The Code of the library template this entity was imported from, or null if the entity\nis not from the library. Read-only — cannot be changed once set. Example: \"vat_returns\".",
            "nullable": true
          },
          "libraryStatus": {
            "$ref": "#/components/schemas/LibraryStatus"
          },
          "isImported": {
            "type": "boolean",
            "description": "True if the tenant has already imported this library item."
          },
          "deprecated": {
            "type": "boolean",
            "description": "True if this library item has been retired. Deprecated items are hidden from the import\nbrowser (so new tasks cannot be created from them) but remain available for revert-to-library\non existing imports."
          },
          "isArchived": {
            "type": "boolean",
            "description": "Indicates whether this service is archived (inactive)"
          },
          "accountingCode": {
            "type": "string",
            "description": "The accounting code for this service",
            "nullable": true
          },
          "defaultManagedByUser": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "serviceScheduleContent": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "proposalContent": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "category": {
            "$ref": "#/components/schemas/ServiceCategory"
          },
          "vatRate": {
            "$ref": "#/components/schemas/VatRate"
          },
          "pricingMode": {
            "$ref": "#/components/schemas/ServicePricingMode"
          },
          "pricingTiers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BillableServicePricingTierDto"
            },
            "description": "Custom pricing tiers defined on this service. Only populated when PricingMode = CustomTiers.",
            "nullable": true
          },
          "stages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BillableServiceStageDto"
            },
            "description": "User-defined workflow stages for this service",
            "nullable": true
          },
          "clientTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientType"
            },
            "description": "The types of clients this service is applicable to.\nAn empty list means the service is applicable to all client types.",
            "nullable": true
          },
          "agentAuthorisations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AgentAuthorisationType"
            },
            "description": "The HMRC agent authorisation types relevant to this service",
            "nullable": true
          },
          "pricing": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BillableServicePricingOptionDto"
            },
            "description": "The pricing options available for this service\nPrice changes will automatically cascade to all ClientBillableService records using this BillableService\n(unless OverridePricing is set on the ClientBillableService), but any PriceAdjustmentPercentage will still be applied",
            "nullable": true
          },
          "pricingFactors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PricingFactorDto"
            },
            "description": "The pricing factors that can affect the service pricing calculations",
            "nullable": true
          },
          "pcrItems": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CodeAndNameDto"
            },
            "description": "Professional clearance request items for this service",
            "nullable": true
          },
          "showKanbanBoard": {
            "type": "boolean",
            "description": "Whether this service should appear on the Boards kanban view"
          },
          "stageCount": {
            "type": "integer",
            "description": "The number of stages defined on this service",
            "format": "int32"
          },
          "recurringTaskCount": {
            "type": "integer",
            "description": "The number of recurring tasks associated with this service",
            "format": "int32"
          },
          "invoiceLineDescriptionTemplate": {
            "type": "string",
            "description": "Smart name token template for invoice line descriptions",
            "nullable": true
          },
          "setupFee": {
            "type": "number",
            "description": "Optional one-off setup fee charged when the service is first billed for a client.\nNull means no setup fee. Used as the default when assigning the service to a client.",
            "format": "double",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "When the service was created",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "description": "When the service was last updated",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response DTO for billable service information"
      },
      "BillableServiceDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BillableServiceDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "BillableServicePricingOptionDto": {
        "type": "object",
        "properties": {
          "frequency": {
            "$ref": "#/components/schemas/BillingFrequency"
          },
          "price": {
            "type": "number",
            "description": "The default price for this billing frequency\nPrice changes will automatically cascade to all ClientBillableService records using this BillableService\n(unless OverridePricing is set on the ClientBillableService, but any PriceAdjustmentPercentage will still be applied)",
            "format": "double"
          },
          "revenueRangeOverrides": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BillableServicePricingOverrideDto"
            },
            "description": "Revenue range-specific pricing overrides",
            "nullable": true
          },
          "tierOverrides": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BillableServicePricingTierOverrideDto"
            },
            "description": "Custom tier-specific pricing overrides. Only used when parent BillableService has PricingMode = CustomTiers.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "DTO for billable service pricing option information"
      },
      "BillableServicePricingOverrideDto": {
        "type": "object",
        "properties": {
          "revenueRangeCode": {
            "type": "string",
            "description": "The revenue range code this override applies to",
            "nullable": true
          },
          "overridePrice": {
            "type": "number",
            "description": "The override price for this revenue range (null to use default price)",
            "format": "double",
            "nullable": true
          },
          "overrideDescription": {
            "type": "string",
            "description": "The override description for this revenue range (null to use default description)",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "DTO for revenue range-specific pricing overrides"
      },
      "BillableServicePricingTierDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this tier",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The name of the tier (e.g. \"1-10 payslips\")",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "The display order for this tier",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "DTO for a custom pricing tier defined on a billable service"
      },
      "BillableServicePricingTierOverrideDto": {
        "type": "object",
        "properties": {
          "tierCode": {
            "type": "string",
            "description": "The code of the pricing tier this override applies to",
            "nullable": true
          },
          "overridePrice": {
            "type": "number",
            "description": "The override price for this tier (null to use default price)",
            "format": "double",
            "nullable": true
          },
          "overrideDescription": {
            "type": "string",
            "description": "The override description for this tier (null to use default description)",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "DTO for a custom tier-specific pricing override"
      },
      "BillableServiceSortField": {
        "enum": [
          "Name",
          "Category",
          "AccountingCode"
        ],
        "type": "string"
      },
      "BillableServiceStageDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this stage",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The display name of this stage",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Optional description of what this stage represents",
            "nullable": true
          },
          "icon": {
            "type": "string",
            "description": "Optional Lucide icon name for visual identification",
            "nullable": true
          },
          "color": {
            "type": "string",
            "description": "Optional hex colour for visual identification",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "The display order for this stage",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "DTO for a user-defined workflow stage on a billable service"
      },
      "BillingAccountResponse": {
        "required": [
          "billingContactUserCode",
          "code",
          "name"
        ],
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code identifier for the billing account.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The display name of the billing account.",
            "nullable": true
          },
          "billingContactUserCode": {
            "type": "string",
            "description": "The code of the user responsible for billing.",
            "nullable": true
          },
          "billingContactName": {
            "type": "string",
            "description": "The display name of the billing contact.",
            "nullable": true
          },
          "billingContactEmail": {
            "type": "string",
            "description": "The email address of the billing contact.",
            "nullable": true
          },
          "billingDay": {
            "type": "integer",
            "description": "The day of the month (1-28) when invoices are generated.",
            "format": "int32"
          },
          "status": {
            "$ref": "#/components/schemas/BillingAccountStatus"
          },
          "mandate": {
            "$ref": "#/components/schemas/MandateSummaryResponse"
          },
          "additionalInvoiceRecipients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InvoiceRecipient"
            },
            "description": "Additional recipients who receive invoices.\nThe billing contact's email is always included automatically.",
            "nullable": true
          },
          "billingAddress": {
            "$ref": "#/components/schemas/BillingAddress"
          },
          "linkedTenants": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CodeAndNameDto"
            },
            "description": "The tenants linked to this billing account.",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "The date and time when the billing account was created.",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "description": "The date and time when the billing account was last updated.",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response model representing a billing account."
      },
      "BillingAccountStatus": {
        "enum": [
          "MandateRequired",
          "Active",
          "Suspended",
          "Closed"
        ],
        "type": "string",
        "description": "Defines the status of a billing account."
      },
      "BillingAddress": {
        "type": "object",
        "properties": {
          "companyName": {
            "maxLength": 200,
            "minLength": 0,
            "type": "string",
            "description": "The company name.",
            "nullable": true
          },
          "addressLine1": {
            "maxLength": 200,
            "minLength": 0,
            "type": "string",
            "description": "The first line of the address.",
            "nullable": true
          },
          "addressLine2": {
            "maxLength": 200,
            "minLength": 0,
            "type": "string",
            "description": "The second line of the address.",
            "nullable": true
          },
          "city": {
            "maxLength": 100,
            "minLength": 0,
            "type": "string",
            "description": "The city.",
            "nullable": true
          },
          "postalCode": {
            "maxLength": 20,
            "minLength": 0,
            "type": "string",
            "description": "The postal code.",
            "nullable": true
          },
          "country": {
            "maxLength": 100,
            "minLength": 0,
            "type": "string",
            "description": "The country.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Represents a billing address."
      },
      "BillingFrequency": {
        "enum": [
          "OneOff",
          "Annual",
          "Quarterly",
          "Monthly"
        ],
        "type": "string"
      },
      "BillingInvoiceStatus": {
        "enum": [
          "Draft",
          "Issued",
          "PaymentPending",
          "Paid",
          "PaymentFailed",
          "Cancelled"
        ],
        "type": "string",
        "description": "Defines the status of a billing invoice."
      },
      "BooleanDisplayMode": {
        "enum": [
          "Toggle",
          "Checkbox",
          "YesNo"
        ],
        "type": "string"
      },
      "BulkApplyServicePackageRequest": {
        "required": [
          "clientCodes"
        ],
        "type": "object",
        "properties": {
          "clientCodes": {
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The client codes to apply this package to"
          },
          "startDate": {
            "type": "string",
            "description": "The start date for the new service assignments",
            "format": "date-time",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/ServiceStatus"
          },
          "createOnboardingTasks": {
            "type": "boolean",
            "description": "Whether to create onboarding tasks for the assigned services. Defaults to true."
          }
        },
        "additionalProperties": false,
        "description": "Request to apply a service package to multiple clients at once"
      },
      "BulkAssignResult": {
        "type": "object",
        "properties": {
          "assignedCount": {
            "type": "integer",
            "format": "int32"
          }
        },
        "additionalProperties": false
      },
      "BulkAssignServiceRequest": {
        "required": [
          "billingFrequency",
          "clientCodes",
          "startDate"
        ],
        "type": "object",
        "properties": {
          "clientCodes": {
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The client codes to assign this service to"
          },
          "billingFrequency": {
            "$ref": "#/components/schemas/BillingFrequency"
          },
          "price": {
            "minimum": 0,
            "type": "number",
            "description": "Optional price override. When omitted, standard pricing is used.",
            "format": "double",
            "nullable": true
          },
          "overridePricing": {
            "type": "boolean",
            "description": "Whether to use a custom price instead of standard pricing.\nWhen true, Price must be provided."
          },
          "startDate": {
            "type": "string",
            "description": "The start date for the new assignments",
            "format": "date-time"
          },
          "status": {
            "$ref": "#/components/schemas/ServiceStatus"
          },
          "autoInvoice": {
            "type": "boolean",
            "description": "Whether the new assignments should automatically generate invoice line items"
          },
          "createOnboardingTasks": {
            "type": "boolean",
            "description": "Whether to create onboarding tasks for the new assignments.\nSet to false when migrating data from another system."
          },
          "stageCode": {
            "type": "string",
            "description": "Optional stage code to set on the new assignments",
            "nullable": true
          },
          "managedByUserCode": {
            "type": "string",
            "description": "Optional managed-by user code",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request to assign a billable service to multiple clients at once"
      },
      "BulkDeleteResult": {
        "type": "object",
        "properties": {
          "deletedCount": {
            "type": "integer",
            "format": "int32"
          }
        },
        "additionalProperties": false
      },
      "BulkDeleteTasksRequest": {
        "required": [
          "codes"
        ],
        "type": "object",
        "properties": {
          "codes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "additionalProperties": false
      },
      "BulkRemoveClientServicesRequest": {
        "required": [
          "assignments"
        ],
        "type": "object",
        "properties": {
          "assignments": {
            "minItems": 1,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientServiceReference"
            },
            "description": "The assignments to remove, identified by client code and assignment code"
          }
        },
        "additionalProperties": false,
        "description": "Request to remove multiple client service assignments"
      },
      "BulkSendDataFormRequest": {
        "type": "object",
        "properties": {
          "clientCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The codes of the clients to send the form to",
            "nullable": true
          },
          "notifyUserCode": {
            "type": "string",
            "description": "The user to notify when clients submit their responses. If not specified, no notification is sent.",
            "nullable": true
          },
          "autoAcceptData": {
            "type": "boolean",
            "description": "When true, submitted data will be automatically accepted and copied to the client record without manual review"
          },
          "message": {
            "type": "string",
            "description": "A message explaining what the client needs to do, included in the notification email",
            "nullable": true
          },
          "recipients": {
            "$ref": "#/components/schemas/EmailRecipientConfig"
          },
          "chaseFrequencyDays": {
            "type": "integer",
            "description": "Override for the chase frequency in days. If not specified, the tenant default is used.",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "DTO for sending a form to multiple clients"
      },
      "BulkUpdateClientServicesRequest": {
        "required": [
          "assignments"
        ],
        "type": "object",
        "properties": {
          "assignments": {
            "minItems": 1,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientServiceReference"
            },
            "description": "The assignments to update, identified by client code and assignment code"
          },
          "price": {
            "minimum": 0,
            "type": "number",
            "description": "New price to set. Null = no change.",
            "format": "double",
            "nullable": true
          },
          "overridePricing": {
            "type": "boolean",
            "description": "Whether to override pricing. Null = no change.",
            "nullable": true
          },
          "billingFrequency": {
            "$ref": "#/components/schemas/BillingFrequency"
          },
          "autoInvoice": {
            "type": "boolean",
            "description": "New auto-invoice setting. Null = no change.",
            "nullable": true
          },
          "stageCode": {
            "type": "string",
            "description": "New stage code. Null = no change. Empty string = clear stage.",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/ServiceStatus"
          }
        },
        "additionalProperties": false,
        "description": "Request to update fields across multiple client service assignments.\nOnly provided (non-null) fields are updated."
      },
      "BulkUpdateClientsRequest": {
        "required": [
          "codes"
        ],
        "type": "object",
        "properties": {
          "codes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of client codes to update"
          },
          "partnerCode": {
            "type": "string",
            "description": "Partner to assign. Null = no change, empty string = unassign, user code = assign.",
            "nullable": true
          },
          "managerCode": {
            "type": "string",
            "description": "Manager to assign. Null = no change, empty string = unassign, user code = assign.",
            "nullable": true
          },
          "associateCode": {
            "type": "string",
            "description": "Associate to assign. Null = no change, empty string = unassign, user code = assign.",
            "nullable": true
          },
          "pclSent": {
            "type": "boolean",
            "description": "PCL sent status. Null = no change.",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/ClientStatus"
          },
          "teamCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Teams to assign. Null = no change, empty array = clear all, team codes = replace.",
            "nullable": true
          },
          "contactByPost": {
            "type": "boolean",
            "description": "Whether the clients can be contacted by post. Null = no change.",
            "nullable": true
          },
          "contactByTelephone": {
            "type": "boolean",
            "description": "Whether the clients can be contacted by telephone. Null = no change.",
            "nullable": true
          },
          "contactByEmail": {
            "type": "boolean",
            "description": "Whether the clients can be contacted by email. Null = no change.",
            "nullable": true
          },
          "contactBySms": {
            "type": "boolean",
            "description": "Whether the clients can be contacted by SMS. Null = no change.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request to bulk update multiple clients. At least one update field must be provided.\nFor PartnerCode, ManagerCode, and AssociateCode: null means \"don't change\", a user code means \"assign\", and an empty string means \"unassign\"."
      },
      "BulkUpdateResult": {
        "type": "object",
        "properties": {
          "updatedCount": {
            "type": "integer",
            "format": "int32"
          }
        },
        "additionalProperties": false
      },
      "BulkUpdateTasksRequest": {
        "required": [
          "codes"
        ],
        "type": "object",
        "properties": {
          "codes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Codes of the tasks to update."
          },
          "status": {
            "$ref": "#/components/schemas/TaskItemStatus"
          },
          "assignedUserCode": {
            "type": "string",
            "description": "Null = no change, empty string = unassign, value = assign to that user.",
            "nullable": true
          },
          "categoryCode": {
            "type": "string",
            "description": "Null = no change, empty string = clear category, value = set to that category.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "BulkUpdateWorkflowStepsRequest": {
        "required": [
          "steps"
        ],
        "type": "object",
        "properties": {
          "steps": {
            "minItems": 1,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowStepReference"
            },
            "description": "The workflow steps to update, identified by task code + group + step number."
          },
          "status": {
            "$ref": "#/components/schemas/TaskItemStatus"
          },
          "assignedUserCode": {
            "type": "string",
            "description": "Null = no change, empty string = unassign, value = assign to that user.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request to bulk-update workflow steps across multiple tasks.\nAt least one of Status or AssignedUserCode must be provided."
      },
      "BusinessDetailsDto": {
        "type": "object",
        "properties": {
          "company": {
            "$ref": "#/components/schemas/CompanyDetailsDto"
          },
          "tradingAs": {
            "maxLength": 100,
            "type": "string",
            "description": "Trading name if different from the registered company name",
            "nullable": true
          },
          "postalAddress": {
            "maxLength": 500,
            "type": "string",
            "description": "Postal/correspondence address (may differ from registered address)",
            "nullable": true
          },
          "invoiceAddress": {
            "maxLength": 500,
            "type": "string",
            "description": "Address to use for invoicing purposes",
            "nullable": true
          },
          "dateOfTrading": {
            "type": "string",
            "description": "The date when the business started trading (may differ from incorporation date)",
            "format": "date-time",
            "nullable": true
          },
          "natureOfBusiness": {
            "maxLength": 200,
            "type": "string",
            "description": "Description of what the business does",
            "nullable": true
          },
          "utr": {
            "type": "string",
            "description": "The business Unique Taxpayer Reference (Corporation Tax UTR).\nFor Individual clients, the personal UTR is stored on the Contact record.",
            "nullable": true
          },
          "vat": {
            "$ref": "#/components/schemas/VatDetailsDto"
          },
          "payeRef": {
            "maxLength": 14,
            "type": "string",
            "description": "PAYE reference number for employers (e.g. 123/AB12345)",
            "nullable": true
          },
          "accountsOfficeRef": {
            "maxLength": 13,
            "type": "string",
            "description": "HMRC Accounts Office reference number",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Business-specific details for clients, including companies and sole traders.\nIncludes UK Companies House registration information, addresses, tax details, and SIC codes.\nThis information is typically populated from Companies House API or accounting platform integrations."
      },
      "ButtonStyleDto": {
        "type": "object",
        "properties": {
          "backgroundColor": {
            "type": "string",
            "description": "Button background color in hex format (e.g., \"#1E88E5\")",
            "nullable": true
          },
          "textColor": {
            "type": "string",
            "description": "Button text color in hex format (e.g., \"#FFFFFF\")",
            "nullable": true
          },
          "hoverBackgroundColor": {
            "type": "string",
            "description": "Button hover background color in hex format",
            "nullable": true
          },
          "hoverTextColor": {
            "type": "string",
            "description": "Button hover text color in hex format",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Button styling configuration for a design theme.\nAll properties are nullable - when null, buttons fall back to theme PrimaryColor/SecondaryColor defaults."
      },
      "ChangeSubscriptionRequest": {
        "required": [
          "packageCode"
        ],
        "type": "object",
        "properties": {
          "packageCode": {
            "minLength": 1,
            "type": "string",
            "description": "The package to subscribe to."
          }
        },
        "additionalProperties": false,
        "description": "Request to change a tenant's subscription to a different package.\nThe pricing tier is automatically determined based on the tenant's active client count."
      },
      "ChecklistItemDto": {
        "type": "object",
        "properties": {
          "text": {
            "type": "string",
            "nullable": true
          },
          "isCompleted": {
            "type": "boolean"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          }
        },
        "additionalProperties": false
      },
      "ClientAgentAuthorisationDto": {
        "type": "object",
        "properties": {
          "authorisationType": {
            "$ref": "#/components/schemas/AgentAuthorisationType"
          },
          "status": {
            "$ref": "#/components/schemas/AgentAuthorisationStatus"
          },
          "isRequired": {
            "type": "boolean",
            "description": "True if any of the client's active or proposed services require this authorisation type"
          },
          "hmrcInvitation": {
            "$ref": "#/components/schemas/HmrcInvitationDetailsDto"
          }
        },
        "additionalProperties": false,
        "description": "Represents one of the 11 HMRC agent authorisation types for a client"
      },
      "ClientApprovalStatus": {
        "enum": [
          "None",
          "Pending",
          "Approved",
          "Rejected"
        ],
        "type": "string"
      },
      "ClientAssociationType": {
        "enum": [
          "None",
          "SpecificClients",
          "AllClients",
          "ClientsWithServices",
          "ClientsWithPipelines"
        ],
        "type": "string"
      },
      "ClientBillableServiceDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this client service assignment",
            "nullable": true
          },
          "billableService": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "billableServiceCategory": {
            "$ref": "#/components/schemas/ServiceCategory"
          },
          "recurringTaskCount": {
            "type": "integer",
            "description": "The number of recurring tasks associated with the billable service",
            "format": "int32"
          },
          "billingFrequency": {
            "$ref": "#/components/schemas/BillingFrequency"
          },
          "price": {
            "type": "number",
            "description": "The base price for this client's service (before any adjustment).\nIf OverridePricing = false: Loaded from BillableService based on BillingFrequency.\nIf OverridePricing = true: Custom base price set by user.\nThe final price after adjustment is in EffectivePrice.",
            "format": "double"
          },
          "overridePricing": {
            "type": "boolean",
            "description": "Indicates whether the pricing is overridden with a custom Price value\nIf true: Price is used as-is, ignoring BillableService pricing\nIf false: Price comes from BillableService, and the client-level adjustment is applied"
          },
          "priceAdjustmentPercentage": {
            "type": "number",
            "description": "Snapshot of the percentage contribution from selected Percentage-mode pricing factors (positive or negative).",
            "format": "double"
          },
          "priceAdjustmentFixedAmount": {
            "type": "number",
            "description": "Snapshot of the absolute currency contribution from selected FixedAmount-mode pricing factors (positive or negative).",
            "format": "double"
          },
          "effectivePrice": {
            "type": "number",
            "description": "Read-only. Effective price = Price + (Price * PriceAdjustmentPercentage / 100) + PriceAdjustmentFixedAmount.\nBoth contributions are always applied — they're snapshots from different pricing factors and can coexist.",
            "format": "double",
            "readOnly": true
          },
          "startDate": {
            "type": "string",
            "description": "The start date for this service",
            "format": "date-time"
          },
          "endDate": {
            "type": "string",
            "description": "The end date for this service (null means ongoing)",
            "format": "date-time",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/ServiceStatus"
          },
          "managedByUser": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "pricingAnswers": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "The pricing factor answers that determined the final price\nKey: Question, Value: Answer",
            "nullable": true
          },
          "pricingTierCode": {
            "type": "string",
            "description": "The code of the selected custom pricing tier. Only present when the BillableService uses CustomTiers pricing mode.",
            "nullable": true
          },
          "stage": {
            "$ref": "#/components/schemas/ClientBillableServiceStageDto"
          },
          "servicePackage": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "servicePackageUsePackagePricing": {
            "type": "boolean",
            "description": "Whether the originating service package uses package-level pricing",
            "nullable": true
          },
          "servicePackagePrice": {
            "type": "number",
            "description": "The package-level price from the originating service package",
            "format": "double",
            "nullable": true
          },
          "servicePackageBillingFrequency": {
            "$ref": "#/components/schemas/BillingFrequency"
          },
          "servicePackageSetupFee": {
            "type": "number",
            "description": "The package-level setup fee from the originating service package",
            "format": "double",
            "nullable": true
          },
          "setupFee": {
            "type": "number",
            "description": "The one-off setup fee for this client's service. Null means no setup fee.\nIf OverrideSetupFee = false: Mirrors the BillableService default at the time of assignment.\nIf OverrideSetupFee = true: Custom setup fee set by user.",
            "format": "double",
            "nullable": true
          },
          "overrideSetupFee": {
            "type": "boolean",
            "description": "Indicates whether the setup fee is overridden with a custom value"
          },
          "setupFeeBilledDate": {
            "type": "string",
            "description": "When the setup fee line item was generated (UTC). Null means not yet billed.",
            "format": "date-time",
            "nullable": true
          },
          "autoInvoice": {
            "type": "boolean",
            "description": "Whether this service automatically generates invoice line items"
          },
          "nextBillingDate": {
            "type": "string",
            "description": "The next date a billable line item will be generated",
            "format": "date-time",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "When the service assignment was created",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "description": "When the service assignment was last updated",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response DTO for client billable service information"
      },
      "ClientBillableServiceDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientBillableServiceDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "ClientBillableServiceSortField": {
        "enum": [
          "Name",
          "Price"
        ],
        "type": "string"
      },
      "ClientBillableServiceStageDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The stage code",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The stage display name",
            "nullable": true
          },
          "icon": {
            "type": "string",
            "description": "Optional Lucide icon name",
            "nullable": true
          },
          "color": {
            "type": "string",
            "description": "Optional hex colour",
            "nullable": true
          },
          "setTime": {
            "type": "string",
            "description": "When this stage was set (UTC)",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Stage information for display on a client's billable service"
      },
      "ClientBillableServiceStageHistoryDto": {
        "type": "object",
        "properties": {
          "fromStage": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "toStage": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "changedBy": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "changedDate": {
            "type": "string",
            "description": "When the change happened (UTC).",
            "format": "date-time"
          },
          "drivenByTask": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          }
        },
        "additionalProperties": false,
        "description": "One stage change in a client billable service's history, newest first. Powers the\ntime-in-stage view: the duration a service spent in a stage is the gap between one row's\nSodiumHQ.DTOs.ClientBillableService.ClientBillableServiceStageHistoryDto.ChangedDate and the next."
      },
      "ClientBillableServiceSummaryDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this client service",
            "nullable": true
          },
          "client": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "billableService": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "stage": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "stageSetTime": {
            "type": "string",
            "description": "When the current stage was set (UTC). Used for calculating time-in-stage on the frontend.",
            "format": "date-time",
            "nullable": true
          },
          "managedByUser": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "tasks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/KanbanTaskDto"
            },
            "description": "Open tasks for this client (not completed or skipped). Only populated in non-verbose mode.",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/ServiceStatus"
          },
          "price": {
            "type": "number",
            "description": "The base price. Only populated when verbose=true.",
            "format": "double",
            "nullable": true
          },
          "effectivePrice": {
            "type": "number",
            "description": "The effective price after adjustments. Only populated when verbose=true.",
            "format": "double",
            "nullable": true
          },
          "overridePricing": {
            "type": "boolean",
            "description": "Whether pricing is overridden. Only populated when verbose=true.",
            "nullable": true
          },
          "billingFrequency": {
            "$ref": "#/components/schemas/BillingFrequency"
          },
          "startDate": {
            "type": "string",
            "description": "The start date. Only populated when verbose=true.",
            "format": "date-time",
            "nullable": true
          },
          "endDate": {
            "type": "string",
            "description": "The end date. Only populated when verbose=true.",
            "format": "date-time",
            "nullable": true
          },
          "autoInvoice": {
            "type": "boolean",
            "description": "Whether auto-invoicing is enabled. Only populated when verbose=true.",
            "nullable": true
          },
          "nextBillingDate": {
            "type": "string",
            "description": "Next billing date. Only populated when verbose=true.",
            "format": "date-time",
            "nullable": true
          },
          "stageIcon": {
            "type": "string",
            "description": "Stage icon (Lucide icon name). Only populated when verbose=true.",
            "nullable": true
          },
          "stageColor": {
            "type": "string",
            "description": "Stage colour (hex). Only populated when verbose=true.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Lightweight projection of a client billable service for kanban board cards.\nContains only the fields needed for board display — not the full ClientBillableServiceDto."
      },
      "ClientBillableServiceSummaryDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientBillableServiceSummaryDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "ClientBillableServiceSummarySortField": {
        "enum": [
          "ClientName",
          "StageSetTime",
          "DueDate"
        ],
        "type": "string"
      },
      "ClientBillingLineItemDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this line item",
            "nullable": true
          },
          "client": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "clientBillableService": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "servicePackage": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "description": {
            "type": "string",
            "description": "The invoice line description",
            "nullable": true
          },
          "quantity": {
            "type": "number",
            "description": "The quantity",
            "format": "double"
          },
          "unitPrice": {
            "type": "number",
            "description": "Snapshot of the effective price at generation",
            "format": "double"
          },
          "vatRate": {
            "$ref": "#/components/schemas/VatRate"
          },
          "accountingCode": {
            "type": "string",
            "description": "The accounting/nominal code",
            "nullable": true
          },
          "periodStart": {
            "type": "string",
            "description": "Start of the service period covered",
            "format": "date-time",
            "nullable": true
          },
          "periodEnd": {
            "type": "string",
            "description": "End of the service period covered",
            "format": "date-time",
            "nullable": true
          },
          "generatedDate": {
            "type": "string",
            "description": "When the line item was generated",
            "format": "date-time"
          },
          "billingDate": {
            "type": "string",
            "description": "Target invoice date",
            "format": "date-time"
          },
          "status": {
            "$ref": "#/components/schemas/ClientBillingLineItemStatus"
          },
          "invoiceSubmissionCode": {
            "type": "string",
            "description": "The invoice submission code this was bundled into (null until invoiced)",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "When the line item was created",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "description": "When the line item was last updated",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response DTO for a billable line item"
      },
      "ClientBillingLineItemDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientBillingLineItemDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "ClientBillingLineItemSortField": {
        "enum": [
          "BillingDate",
          "GeneratedDate",
          "Status",
          "UnitPrice"
        ],
        "type": "string"
      },
      "ClientBillingLineItemStatus": {
        "enum": [
          "Pending",
          "Approved",
          "Invoiced",
          "Cancelled"
        ],
        "type": "string"
      },
      "ClientBillingSettingsDto": {
        "type": "object",
        "properties": {
          "clientBillingEnabled": {
            "type": "boolean",
            "description": "Whether recurring client billing features are enabled for this tenant"
          },
          "defaultInvoiceDayOfMonth": {
            "type": "integer",
            "description": "Default day of month (1-28) for automatic invoicing on new clients",
            "format": "int32",
            "nullable": true
          },
          "defaultInvoicePaymentTermDays": {
            "type": "integer",
            "description": "Default payment terms in days for generated invoices on new clients",
            "format": "int32",
            "nullable": true
          },
          "defaultLineItemApprovalRequired": {
            "type": "boolean",
            "description": "Default for whether generated line items require manual approval before invoicing on new clients"
          },
          "defaultAccountingCode": {
            "type": "string",
            "description": "Default accounting/nominal code for new billable services and manual line items",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Tenant-level settings for recurring client billing and invoicing defaults"
      },
      "ClientConfirmationDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "The workflow step ID",
            "format": "int32"
          },
          "stepName": {
            "type": "string",
            "description": "The name of the workflow step",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/TaskItemStatus"
          },
          "task": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "client": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "taskCategory": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "groupName": {
            "type": "string",
            "description": "The workflow group name",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "When the confirmation step was created",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "description": "When the confirmation step was last updated",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Summary DTO for a client confirmation workflow step"
      },
      "ClientConfirmationDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientConfirmationDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "ClientConfirmationExecutionStateDto": {
        "type": "object",
        "properties": {
          "createdAt": {
            "type": "string",
            "description": "UTC timestamp of when the confirmation email was sent.",
            "format": "date-time"
          },
          "confirmedAt": {
            "type": "string",
            "description": "UTC timestamp of when the client confirmed.",
            "format": "date-time",
            "nullable": true
          },
          "confirmedByEmail": {
            "type": "string",
            "description": "Email address of the recipient who confirmed (from magic link token).",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Execution state for a ClientConfirmation workflow step.\nRead-only - written by the system during step execution."
      },
      "ClientConfirmationSortField": {
        "enum": [
          "StepName",
          "CreatedDate",
          "Date"
        ],
        "type": "string"
      },
      "ClientConfirmationStepConfigDto": {
        "required": [
          "buttonText",
          "messageHtml",
          "thankYouMessageHtml"
        ],
        "type": "object",
        "properties": {
          "subjectLine": {
            "maxLength": 500,
            "type": "string",
            "description": "Optional email subject line override. When set, replaces the content block's subject.\nSupports Liquid template syntax (e.g., \"Action required — {{ Client.Name }}\").\nWhen null/empty, the subject from the ClientPortalSettings content block is used.",
            "nullable": true
          },
          "messageHtml": {
            "minLength": 1,
            "type": "string",
            "description": "HTML message displayed on the public confirmation page.\nSupports Liquid template syntax (e.g., {{ Client.Name }})."
          },
          "buttonText": {
            "maxLength": 200,
            "minLength": 1,
            "type": "string",
            "description": "Text for the confirmation button on the public page."
          },
          "thankYouMessageHtml": {
            "minLength": 1,
            "type": "string",
            "description": "HTML message displayed after the client confirms.\nSupports Liquid template syntax."
          },
          "recipientContactTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientContactType"
            },
            "description": "Client contact types to send the confirmation email to.",
            "nullable": true
          },
          "additionalEmailAddresses": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Static email addresses to send the confirmation email to.",
            "nullable": true
          },
          "notifyAssigneeOnConfirmation": {
            "type": "boolean",
            "description": "Whether to send a notification to the step's assigned user when the client confirms."
          },
          "chaseFrequencyDays": {
            "type": "integer",
            "description": "Override for how often (in days) to chase this confirmation.\nWhen null, the tenant-level default is used.",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Configuration for ClientConfirmation workflow steps.\nEmail template is configured in ClientPortalSettings, not per-step."
      },
      "ClientContactDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this relationship (uses the contact's code)",
            "nullable": true
          },
          "role": {
            "type": "string",
            "description": "The role of the contact within this client relationship",
            "nullable": true
          },
          "resignedDate": {
            "type": "string",
            "description": "Date the contact resigned their officer role for this client (from Companies House).\nNull while still an active officer.",
            "format": "date",
            "nullable": true
          },
          "ceasedDate": {
            "type": "string",
            "description": "Date the contact ceased being a Person with Significant Control for this client\n(from Companies House). Null while still an active PSC. Independent of resignation —\na person can hold both roles and end them on different dates.",
            "format": "date",
            "nullable": true
          },
          "types": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientContactType"
            },
            "description": "The type of contact relationship",
            "nullable": true
          },
          "contact": {
            "$ref": "#/components/schemas/ContactDto"
          },
          "client": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "individualClient": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "hasPortalAccess": {
            "type": "boolean",
            "description": "Whether this contact has access to the client portal for this client."
          },
          "amlContactId": {
            "type": "string",
            "description": "The contact's ID in the AML platform. Null if not yet pushed.",
            "nullable": true
          },
          "lastPortalAccessDate": {
            "type": "string",
            "description": "When this contact last accessed the client portal for this client.",
            "format": "date-time",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "When the relationship was created",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "description": "When the relationship was last updated",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response DTO for client-contact relationship information"
      },
      "ClientContactDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientContactDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "ClientContactSortField": {
        "enum": [
          "Name",
          "Role"
        ],
        "type": "string"
      },
      "ClientContactType": {
        "enum": [
          "Main",
          "Billing",
          "Payroll",
          "Accounts",
          "Director",
          "Psc"
        ],
        "type": "string"
      },
      "ClientCsvTargetField": {
        "enum": [
          "Name",
          "Code",
          "Type",
          "Status",
          "Email",
          "Telephone",
          "InternalReference",
          "CanContactPost",
          "CanContactTelephone",
          "CanContactEmail",
          "CanContactSms",
          "PclSent",
          "Manager",
          "Partner",
          "Associate",
          "CompanyNumber",
          "CompaniesHouseAuthenticationCode",
          "VatNumber",
          "VatRegistered",
          "VatRegDate",
          "VatScheme",
          "VatReportingPeriod",
          "Utr",
          "SelfAssessmentUtr",
          "CompanyUtr",
          "NiNumber",
          "PayeRef",
          "AccountsOfficeRef",
          "TradingAs",
          "NatureOfBusiness",
          "IncorporationDate",
          "RegisteredAddress",
          "PostalAddress",
          "InvoiceAddress",
          "RegisteredAddressLine1",
          "RegisteredAddressLine2",
          "RegisteredAddressLine3",
          "RegisteredAddressCity",
          "RegisteredAddressPostCode",
          "RegisteredAddressCountry",
          "PostalAddressLine1",
          "PostalAddressLine2",
          "PostalAddressLine3",
          "PostalAddressCity",
          "PostalAddressPostCode",
          "PostalAddressCountry",
          "InvoiceAddressLine1",
          "InvoiceAddressLine2",
          "InvoiceAddressLine3",
          "InvoiceAddressCity",
          "InvoiceAddressPostCode",
          "InvoiceAddressCountry",
          "ContactName",
          "ContactTitle",
          "ContactFirstName",
          "ContactMiddleName",
          "ContactLastName",
          "ContactEmail",
          "ContactPhone",
          "ContactMobile",
          "ContactDateOfBirth",
          "PersonalCode",
          "ContactRelationships",
          "Team",
          "Website",
          "ContactNationality",
          "ContactMaritalStatus",
          "ContactAddress",
          "VatPeriodEnd",
          "Notes",
          "ImportantNotes",
          "SicCodes",
          "DateOfTrading",
          "TradingAsSoleTrader",
          "LinkedInUrl",
          "FacebookUrl",
          "TwitterUrl",
          "InstagramUrl",
          "AuthSelfAssessment",
          "AuthCorporationTax",
          "AuthPayeForEmployers",
          "AuthIndividualPayAsYouEarn",
          "AuthVat",
          "AuthConstructionIndustryScheme",
          "AuthTaxCredits",
          "AuthHighIncomeChildBenefitCharge",
          "AuthMakingTaxDigitalIncomeTax",
          "AuthMakingTaxDigitalVat",
          "AuthTrusts",
          "AmlClientId",
          "Notes2",
          "Notes3",
          "Notes4",
          "Notes5",
          "VatFlatRateScheme"
        ],
        "type": "string"
      },
      "ClientDateDto": {
        "type": "object",
        "properties": {
          "dateType": {
            "$ref": "#/components/schemas/ClientDateType"
          },
          "date": {
            "type": "string",
            "description": "The actual date value for this client date type",
            "format": "date",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Optional additional notes or context about this date",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Represents an important date associated with a client, such as year-end, accounts due date, or VAT return date.\nThese dates are used for scheduling recurring tasks and compliance deadlines specific to the client's accounting calendar."
      },
      "ClientDateSourceType": {
        "enum": [
          "KeyDate",
          "CustomField"
        ],
        "type": "string"
      },
      "ClientDateType": {
        "enum": [
          "IncorporationDate",
          "YearEnd",
          "AccountsNextDue",
          "AccountsNextPeriodStart",
          "AccountsNextPeriodEnd",
          "AccountsLastPeriodFiled",
          "AccountsLastPeriodStart",
          "AccountsLastPeriodEnd",
          "AccountsLastMadeUpTo",
          "ConfirmationStatementDue",
          "ConfirmationStatementNextMadeUpTo",
          "LastConfirmationStatementFiled",
          "LastConfirmationStatementMadeUpTo",
          "NextVatReturnDue",
          "NextVatPeriodEndQuarterly",
          "NextVatReturnDueQuarterly",
          "NextVatPeriodEndMonthly",
          "NextVatReturnDueMonthly",
          "NextTaxQuarterPeriodEnd",
          "NextTaxQuarterSubmissionDeadline",
          "NextPayeCisFilingDue",
          "PensionReEnrolmentDate"
        ],
        "type": "string"
      },
      "ClientDocumentDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this document",
            "nullable": true
          },
          "client": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "category": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "title": {
            "type": "string",
            "description": "The title of the document",
            "nullable": true
          },
          "summary": {
            "type": "string",
            "description": "A brief summary or description of the document",
            "nullable": true
          },
          "date": {
            "type": "string",
            "description": "The date the document is dated (not the creation date)",
            "format": "date"
          },
          "originalFileName": {
            "type": "string",
            "description": "Original file name provided during upload",
            "nullable": true
          },
          "contentType": {
            "type": "string",
            "description": "MIME type of the document (e.g., application/pdf)",
            "nullable": true
          },
          "fileSize": {
            "type": "integer",
            "description": "File size in bytes",
            "format": "int64"
          },
          "storageType": {
            "$ref": "#/components/schemas/StorageType"
          },
          "reviewStatus": {
            "$ref": "#/components/schemas/ReviewStatus"
          },
          "uploadedByContact": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "reviewedByUser": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "reviewedDate": {
            "type": "string",
            "description": "When this document was reviewed",
            "format": "date-time",
            "nullable": true
          },
          "clientApprovalStatus": {
            "$ref": "#/components/schemas/ClientApprovalStatus"
          },
          "clientApprovalRequestedByUser": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "clientApprovalRequestedDate": {
            "type": "string",
            "description": "When client approval was requested",
            "format": "date-time",
            "nullable": true
          },
          "clientApprovalNote": {
            "type": "string",
            "description": "Note provided by the client when approving or rejecting",
            "nullable": true
          },
          "clientApprovalContact": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "clientApprovalDate": {
            "type": "string",
            "description": "When the client approved or rejected this document",
            "format": "date-time",
            "nullable": true
          },
          "clientApprovalIpAddress": {
            "type": "string",
            "description": "IP address of the client who approved or rejected this document",
            "nullable": true
          },
          "clientApprovalEmail": {
            "type": "string",
            "description": "Email address of the recipient who approved or rejected (from magic link token).",
            "nullable": true
          },
          "visibleInClientPortal": {
            "type": "boolean",
            "description": "Whether this document is visible to the client in the portal.\nDoes not affect visibility in external storage providers — only controls portal access."
          },
          "downloadUrl": {
            "type": "string",
            "description": "URL for downloading/viewing the document.\nFor Azure Blob: a time-limited SAS URL.\nFor External: a link to the file in the external platform.",
            "nullable": true
          },
          "portalFolderPath": {
            "type": "string",
            "description": "Folder path controlling where this document appears in the client portal.\nFormat: \"/\" separated folder names, e.g. \"Tax Returns/2026\".\nNull for root-level documents.",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "When the document record was created in the system",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "description": "When the document record was last updated",
            "format": "date-time",
            "nullable": true
          },
          "lastChasedDate": {
            "type": "string",
            "description": "When this document approval was last chased. Null if never chased.",
            "format": "date-time",
            "nullable": true
          },
          "chaseFrequencyDays": {
            "type": "integer",
            "description": "How often (in days) this document approval is chased. Null means chasing is disabled.",
            "format": "int32",
            "nullable": true
          },
          "nextChaseDate": {
            "type": "string",
            "description": "When this document approval is next due for chasing.",
            "format": "date-time",
            "nullable": true
          },
          "documentRequest": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "task": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "taskCategory": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          }
        },
        "additionalProperties": false,
        "description": "Represents a document associated with a client, such as letters, engagement letters, proposals, or other correspondence.\nDocuments may be stored in blob storage or an external platform (e.g., Google Drive)."
      },
      "ClientDocumentDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientDocumentDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "ClientDocumentPortalViewResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientDocumentDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          },
          "folders": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PortalFolderDto"
            },
            "description": "Sub-folders at the current navigation level. Empty when there are no sub-folders.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Paginated list of client documents with portal folder navigation, as seen by the client.\nUsed by the \"Portal View\" preview in the main web app."
      },
      "ClientDocumentSortField": {
        "enum": [
          "Title",
          "Date",
          "UpdatedDate",
          "CreatedDate"
        ],
        "type": "string"
      },
      "ClientDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The client's unique Code within the tenant",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The name of the client",
            "nullable": true
          },
          "type": {
            "$ref": "#/components/schemas/ClientType"
          },
          "manager": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "partner": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "associate": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "teams": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CodeAndNameDto"
            },
            "description": "The teams assigned to this client",
            "nullable": true
          },
          "internalReference": {
            "type": "string",
            "description": "Optional internal reference number/code for the client",
            "nullable": true
          },
          "revenueRangeCode": {
            "type": "string",
            "description": "The revenue range code for this client",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/ClientStatus"
          },
          "accountingCustomerCode": {
            "type": "string",
            "description": "The customer code/ID from the connected accounting platform",
            "nullable": true
          },
          "directDebitMandateId": {
            "type": "string",
            "description": "The mandate ID from the connected direct debit platform",
            "nullable": true
          },
          "amlClientId": {
            "type": "string",
            "description": "The client/account ID from the connected AML platform",
            "nullable": true
          },
          "amlClientName": {
            "type": "string",
            "description": "The display name of the client in the connected AML platform",
            "nullable": true
          },
          "email": {
            "type": "string",
            "description": "The email address for the client",
            "nullable": true
          },
          "telephone": {
            "type": "string",
            "description": "The telephone number for the client",
            "nullable": true
          },
          "contactPreferences": {
            "$ref": "#/components/schemas/ContactPreferencesDto"
          },
          "invoiceDayOfMonth": {
            "type": "integer",
            "description": "Day of month (1-28) for automatic invoicing. Null disables auto-invoicing.",
            "format": "int32",
            "nullable": true
          },
          "invoicePaymentTermDays": {
            "type": "integer",
            "description": "Payment terms in days for generated invoices",
            "format": "int32",
            "nullable": true
          },
          "lineItemApprovalRequired": {
            "type": "boolean",
            "description": "Null = use tenant default. True = require manual approval. False = auto-approve.",
            "nullable": true
          },
          "primaryContactName": {
            "type": "string",
            "description": "The full name of the primary (main) contact for this client",
            "nullable": true
          },
          "primaryContactEmail": {
            "type": "string",
            "description": "The email address of the primary (main) contact for this client",
            "nullable": true
          },
          "latestNoteContent": {
            "type": "string",
            "description": "The most recent note/comment on this client",
            "nullable": true
          },
          "latestNoteDate": {
            "type": "string",
            "description": "When the most recent note was created",
            "format": "date-time",
            "nullable": true
          },
          "pclSent": {
            "type": "boolean",
            "description": "Indicates whether a Professional Clearance Letter has been sent for this client"
          },
          "snoozeChasesUntil": {
            "type": "string",
            "description": "Automated chase emails are suppressed until this date (chasing resumes on the date itself). Null = not snoozed.",
            "format": "date-time",
            "nullable": true
          },
          "companiesHouseLastSyncedDate": {
            "type": "string",
            "description": "When Companies House data was last synced for this client",
            "format": "date-time",
            "nullable": true
          },
          "documentsPendingClientApprovalCount": {
            "type": "integer",
            "description": "Number of documents awaiting client approval",
            "format": "int32"
          },
          "documentsPendingUserReviewCount": {
            "type": "integer",
            "description": "Number of documents uploaded by client via portal awaiting user review",
            "format": "int32"
          },
          "portalUserCount": {
            "type": "integer",
            "description": "Number of portal users with access to this client",
            "format": "int32"
          },
          "outstandingDocumentRequestCount": {
            "type": "integer",
            "description": "Number of document requests in Open or Submitted status",
            "format": "int32"
          },
          "documentRequestsPendingReviewCount": {
            "type": "integer",
            "description": "Number of document requests in Submitted status awaiting staff review",
            "format": "int32"
          },
          "pendingConfirmationCount": {
            "type": "integer",
            "description": "Number of client confirmation workflow steps awaiting the client's response",
            "format": "int32"
          },
          "createdDate": {
            "type": "string",
            "description": "When the client was created",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "description": "When the client was last updated",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response DTO for client information"
      },
      "ClientDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "ClientEmailRuleDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this rule",
            "nullable": true
          },
          "client": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "value": {
            "type": "string",
            "description": "The email address, domain, or message ID to match.\nEmail addresses (contain '@') match that specific participant.\nDomains (no '@', not a GUID) match all emails from that domain.\nMessage IDs (valid GUID) pin a specific email to this client.",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "When the rule was created",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "description": "When the rule was last updated",
            "format": "date-time",
            "nullable": true
          },
          "isAutoAdded": {
            "type": "boolean",
            "description": "Whether this rule was automatically added from client/contact email addresses.\nAuto-added rules are maintained by the system and updated when the source email changes."
          }
        },
        "additionalProperties": false,
        "description": "A rule that associates emails with a client.\nThe value determines the matching behaviour:\nemail addresses (contain '@') match that specific participant,\ndomains (no '@', not a GUID) match all emails from that domain,\nmessage IDs (valid GUID) pin a specific email to this client.\nThe same value can be a rule for multiple clients."
      },
      "ClientEmailRuleDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientEmailRuleDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "ClientEmailRuleSortField": {
        "enum": [
          "Value",
          "CreatedDate"
        ],
        "type": "string"
      },
      "ClientImportRequestDto": {
        "type": "object",
        "properties": {
          "externalIds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of external IDs to import from the third-party platform.\nWhen importAll=false, only clients with these IDs will be imported.\nWhen importAll=true, this list is ignored and all available clients are imported.",
            "nullable": true,
            "example": [
              "ext-123",
              "ext-456"
            ]
          }
        },
        "additionalProperties": false,
        "description": "Request to import clients from a third-party platform"
      },
      "ClientInvoiceSubmissionDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this submission",
            "nullable": true
          },
          "client": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "billingDate": {
            "type": "string",
            "description": "The target invoice date",
            "format": "date-time"
          },
          "submittedAt": {
            "type": "string",
            "description": "When the invoice was pushed to the platform",
            "format": "date-time",
            "nullable": true
          },
          "externalInvoiceId": {
            "type": "string",
            "description": "The invoice ID from the accounting platform",
            "nullable": true
          },
          "externalInvoiceNumber": {
            "type": "string",
            "description": "The invoice number from the accounting platform",
            "nullable": true
          },
          "externalInvoiceUrl": {
            "type": "string",
            "description": "Direct URL to view the invoice on the accounting platform",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/ClientInvoiceSubmissionStatus"
          },
          "errorMessage": {
            "type": "string",
            "description": "Failure reason if push failed",
            "nullable": true
          },
          "lineCount": {
            "type": "integer",
            "description": "Number of line items in this submission",
            "format": "int32"
          },
          "totalAmount": {
            "type": "number",
            "description": "Total amount of all line items (Quantity × UnitPrice)",
            "format": "double"
          },
          "lineItems": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientBillingLineItemDto"
            },
            "description": "The billing line items in this submission",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "When the submission was created",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "description": "When the submission was last updated",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response DTO for an invoice submission"
      },
      "ClientInvoiceSubmissionDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientInvoiceSubmissionDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "ClientInvoiceSubmissionSortField": {
        "enum": [
          "BillingDate",
          "SubmittedAt",
          "Status",
          "TotalAmount"
        ],
        "type": "string"
      },
      "ClientInvoiceSubmissionStatus": {
        "enum": [
          "Pending",
          "Submitted",
          "Failed",
          "Projected"
        ],
        "type": "string"
      },
      "ClientLinkDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this link",
            "nullable": true
          },
          "url": {
            "type": "string",
            "description": "The URL of the link",
            "nullable": true
          },
          "linkType": {
            "$ref": "#/components/schemas/LinkType"
          },
          "displayName": {
            "type": "string",
            "description": "Optional display name shown as anchor text instead of the URL",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "When the link was created",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "description": "When the link was last updated",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response DTO for client link information"
      },
      "ClientLinkDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientLinkDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "ClientLinkSortField": {
        "enum": [
          "LinkType"
        ],
        "type": "string"
      },
      "ClientNoteSortField": {
        "enum": [
          "Date",
          "UpdatedDate"
        ],
        "type": "string"
      },
      "ClientPipelineDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this pipeline card",
            "nullable": true
          },
          "client": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "pipeline": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "stage": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "stageIcon": {
            "type": "string",
            "description": "Stage icon (Lucide icon name)",
            "nullable": true
          },
          "stageColor": {
            "type": "string",
            "description": "Stage colour (hex)",
            "nullable": true
          },
          "stageSetTime": {
            "type": "string",
            "description": "When the current stage was set (UTC)",
            "format": "date-time",
            "nullable": true
          },
          "managedByUser": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "startDate": {
            "type": "string",
            "description": "The date the client entered the pipeline",
            "format": "date-time"
          },
          "endDate": {
            "type": "string",
            "description": "The date the client left the pipeline (optional)",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response DTO for a client's placement on a sales pipeline (a kanban card)."
      },
      "ClientPipelineDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientPipelineDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "ClientPipelineSortField": {
        "enum": [
          "Name",
          "StageSetTime",
          "StartDate"
        ],
        "type": "string"
      },
      "ClientPipelineSummaryDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this pipeline card",
            "nullable": true
          },
          "client": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "pipeline": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "stage": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "stageIcon": {
            "type": "string",
            "description": "Stage icon (Lucide icon name)",
            "nullable": true
          },
          "stageColor": {
            "type": "string",
            "description": "Stage colour (hex)",
            "nullable": true
          },
          "stageSetTime": {
            "type": "string",
            "description": "When the current stage was set (UTC). Used for calculating time-in-stage on the frontend.",
            "format": "date-time",
            "nullable": true
          },
          "managedByUser": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "startDate": {
            "type": "string",
            "description": "The date the client entered the pipeline",
            "format": "date-time",
            "nullable": true
          },
          "tasks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/KanbanTaskDto"
            },
            "description": "Open tasks for this client (not completed or skipped).",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Lightweight projection of a client pipeline card for kanban board display.\nReuses SodiumHQ.DTOs.ClientBillableService.KanbanTaskDto for the open-tasks list."
      },
      "ClientPipelineSummaryDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientPipelineSummaryDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "ClientPipelineSummarySortField": {
        "enum": [
          "ClientName",
          "StageSetTime",
          "DueDate"
        ],
        "type": "string"
      },
      "ClientPortalSettingsDto": {
        "type": "object",
        "properties": {
          "portalTitle": {
            "type": "string",
            "description": "The title displayed on the client portal",
            "nullable": true
          },
          "designTheme": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "iconImageAsset": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "showInvoices": {
            "type": "boolean",
            "description": "Whether portal users can view their invoices. Requires the tenant to be connected to an accounting provider and the client to be mapped to an accounting client."
          },
          "showServices": {
            "type": "boolean",
            "description": "Whether portal users can view the services set up for them in Sodium, including prices and dates."
          },
          "invitationEmailContentBlock": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "useIntroPageContentBlock": {
            "type": "boolean",
            "description": "When true, the intro page uses the content block. When false, it uses IntroPageText."
          },
          "introPageContentBlock": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "introPageText": {
            "type": "string",
            "description": "Raw HTML content for the intro page (when UseIntroPageContentBlock is false)",
            "nullable": true
          },
          "notifyManagerOnClientDocumentUpload": {
            "type": "boolean",
            "description": "Whether to send an email notification to the client's manager when a document is uploaded via the portal"
          },
          "url": {
            "type": "string",
            "description": "The URL for the client portal (e.g. https://tenantcode.sodiumportal.com)",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Client portal settings for the tenant"
      },
      "ClientPreviewDataFormRequest": {
        "type": "object",
        "properties": {
          "clientCode": {
            "type": "string",
            "description": "The client code to preview the form as.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request to create a client-context preview link for a data form."
      },
      "ClientRequestSettingsDto": {
        "type": "object",
        "properties": {
          "documentApprovalEmailContentBlock": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "documentRequestOpenedEmailContentBlock": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "documentRequestRejectedEmailContentBlock": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "documentRequestSubmittedEmailContentBlock": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "clientConfirmationEmailContentBlock": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "clientChaseEmailContentBlock": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "dataFormSubmissionEmailContentBlock": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "chaseDocumentRequestFrequencyDays": {
            "type": "integer",
            "description": "How often (in days) to chase open document requests",
            "format": "int32",
            "nullable": true
          },
          "chaseDocumentApprovalFrequencyDays": {
            "type": "integer",
            "description": "How often (in days) to chase pending document approvals",
            "format": "int32",
            "nullable": true
          },
          "chaseClientConfirmationFrequencyDays": {
            "type": "integer",
            "description": "How often (in days) to chase pending client confirmations",
            "format": "int32",
            "nullable": true
          },
          "chaseDataFormSubmissionFrequencyDays": {
            "type": "integer",
            "description": "How often (in days) to chase pending data form submissions",
            "format": "int32",
            "nullable": true
          },
          "hmrcAuthorisationRequestEmailContentBlock": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "chaseHmrcAuthorisationFrequencyDays": {
            "type": "integer",
            "description": "How often (in days) to chase pending HMRC agent authorisation requests",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Client request and chasing settings for the tenant"
      },
      "ClientResponsivenessReportDto": {
        "type": "object",
        "properties": {
          "summary": {
            "$ref": "#/components/schemas/ClientResponsivenessSummaryDto"
          },
          "rows": {
            "$ref": "#/components/schemas/ClientResponsivenessRowDtoPagedResult"
          },
          "generatedAt": {
            "type": "string",
            "description": "When the report was generated (UTC).",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "The Client Responsiveness report: how fast clients answer the client-facing steps we send\nthem (confirmations, document requests, data forms, approvals) and how much chasing it takes."
      },
      "ClientResponsivenessRowDto": {
        "type": "object",
        "properties": {
          "groupKind": {
            "$ref": "#/components/schemas/ReportGroupKind"
          },
          "groupCode": {
            "type": "string",
            "description": "Entity code (client/service code, or step type name). Null for null buckets.",
            "nullable": true
          },
          "groupName": {
            "type": "string",
            "description": "Display name for the group.",
            "nullable": true
          },
          "stepCount": {
            "type": "integer",
            "description": "Client-facing steps completed in the window for this group.",
            "format": "int32"
          },
          "avgResponseDays": {
            "type": "number",
            "description": "Average days from sent to completed. Null when no step carries a start timestamp.",
            "format": "double",
            "nullable": true
          },
          "medianResponseDays": {
            "type": "number",
            "description": "Median days from sent to completed.",
            "format": "double",
            "nullable": true
          },
          "totalChases": {
            "type": "integer",
            "description": "Total chase messages sent for this group's steps.",
            "format": "int32"
          },
          "chasedPct": {
            "type": "number",
            "description": "Percentage of this group's steps that needed at least one chase.",
            "format": "double"
          },
          "worstCaseDays": {
            "type": "number",
            "description": "Slowest response in days for this group.",
            "format": "double",
            "nullable": true
          },
          "worstTask": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          }
        },
        "additionalProperties": false,
        "description": "One row of the Client Responsiveness breakdown table."
      },
      "ClientResponsivenessRowDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientResponsivenessRowDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "ClientResponsivenessSummaryDto": {
        "type": "object",
        "properties": {
          "stepCount": {
            "type": "integer",
            "description": "Client-facing steps completed in the window.",
            "format": "int32"
          },
          "avgResponseDays": {
            "type": "number",
            "description": "Average days from a step being sent to the client completing it. Null when no\ncompleted step carries a start timestamp.",
            "format": "double",
            "nullable": true
          },
          "medianResponseDays": {
            "type": "number",
            "description": "Median days from sent to completed.",
            "format": "double",
            "nullable": true
          },
          "totalChases": {
            "type": "integer",
            "description": "Total chase messages sent for the cohort's steps.",
            "format": "int32"
          },
          "chasedPct": {
            "type": "number",
            "description": "Percentage of cohort steps that needed at least one chase.",
            "format": "double"
          },
          "outstandingCount": {
            "type": "integer",
            "description": "Client-facing steps currently waiting on a client right now.",
            "format": "int32"
          },
          "oldestOutstandingDays": {
            "type": "number",
            "description": "Age in days of the oldest currently-outstanding step. Null when none.",
            "format": "double",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Headline KPIs for the Client Responsiveness report."
      },
      "ClientServiceReference": {
        "required": [
          "clientCode",
          "code"
        ],
        "type": "object",
        "properties": {
          "clientCode": {
            "minLength": 1,
            "type": "string",
            "description": "The client code"
          },
          "code": {
            "minLength": 1,
            "type": "string",
            "description": "The ClientBillableService assignment code"
          }
        },
        "additionalProperties": false,
        "description": "Identifies a specific ClientBillableService assignment by its client code and service assignment code.\nBoth are required because the assignment code is only unique within a client."
      },
      "ClientSettingsDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique identifier for the settings",
            "nullable": true
          },
          "companiesHouseSync_Enabled": {
            "type": "boolean",
            "description": "Controls whether Companies House data for the tenant's linked clients is kept up to date\nautomatically from the Companies House streaming feed."
          },
          "clientManager_Enabled": {
            "type": "boolean",
            "description": "Whether the client manager field is enabled for clients"
          },
          "clientManager_Label": {
            "type": "string",
            "description": "Optional custom label for the client manager field. Null means use the default.",
            "nullable": true
          },
          "partner_Enabled": {
            "type": "boolean",
            "description": "Whether the partner field is enabled for clients"
          },
          "partner_Label": {
            "type": "string",
            "description": "Optional custom label for the partner field. Null means use the default.",
            "nullable": true
          },
          "associate_Enabled": {
            "type": "boolean",
            "description": "Whether the associate field is enabled for clients"
          },
          "associate_Label": {
            "type": "string",
            "description": "Optional custom label for the associate field. Null means use the default.",
            "nullable": true
          },
          "internalReference_Enabled": {
            "type": "boolean",
            "description": "Whether the internal reference field is enabled for clients"
          },
          "internalReference_ForceUnique": {
            "type": "boolean",
            "description": "Whether to force internal references to be unique across all clients"
          },
          "internalReference_AutoGenerate": {
            "type": "boolean",
            "description": "Whether to auto-generate the internal reference from the client code on creation"
          },
          "externalLinks_Enabled": {
            "type": "boolean",
            "description": "Whether external links are enabled for clients"
          },
          "team_Enabled": {
            "type": "boolean",
            "description": "Whether the team field is enabled for clients"
          }
        },
        "additionalProperties": false,
        "description": "Tenant-level configuration for client field visibility and behavior"
      },
      "ClientSortField": {
        "enum": [
          "Name",
          "InternalReference"
        ],
        "type": "string"
      },
      "ClientStatus": {
        "enum": [
          "Active",
          "Inactive",
          "Prospect",
          "LostProspect"
        ],
        "type": "string"
      },
      "ClientThirdPartyMappingDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The client's unique code within the tenant",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The name of the client",
            "nullable": true
          },
          "accountingCustomerCode": {
            "type": "string",
            "description": "The customer code/ID from the connected accounting platform",
            "nullable": true
          },
          "directDebitMandateId": {
            "type": "string",
            "description": "The mandate ID from the connected direct debit platform",
            "nullable": true
          },
          "amlClientId": {
            "type": "string",
            "description": "The client/account ID from the connected AML platform",
            "nullable": true
          },
          "amlClientName": {
            "type": "string",
            "description": "The display name of the client in the connected AML platform",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Lightweight DTO for viewing client third-party platform mappings"
      },
      "ClientThirdPartyMappingDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientThirdPartyMappingDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "ClientThirdPartyMappingSortField": {
        "enum": [
          "Name"
        ],
        "type": "string"
      },
      "ClientType": {
        "enum": [
          "PrivateLimitedCompany",
          "PublicLimitedCompany",
          "LimitedLiabilityPartnership",
          "Partnership",
          "Individual",
          "Trust",
          "Charity",
          "SoleTrader"
        ],
        "type": "string"
      },
      "CodeAndNameDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "Company": {
        "type": "object",
        "properties": {
          "companyNumber": {
            "type": "string",
            "nullable": true
          },
          "companyName": {
            "type": "string",
            "nullable": true
          },
          "type": {
            "type": "string",
            "nullable": true
          },
          "companyStatus": {
            "type": "string",
            "nullable": true
          },
          "dateOfCreation": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "jurisdiction": {
            "type": "string",
            "nullable": true
          },
          "registeredOfficeAddress": {
            "$ref": "#/components/schemas/CompanyAddress"
          },
          "lastFullMembersListDate": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "nextDue": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "nextMadeUpToDate": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "accountingReferenceDate": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "nextAccountsDue": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "nextAccountsMadeUpTo": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "nextAccountsPeriodStart": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "lastAccountsMadeUpTo": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "hasCharges": {
            "type": "boolean"
          },
          "hasInsolvencyHistory": {
            "type": "boolean"
          },
          "isUndeliverableRegisteredOfficeAddress": {
            "type": "boolean"
          },
          "sicCodes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SicCode"
            },
            "nullable": true
          },
          "canFile": {
            "type": "boolean"
          },
          "etag": {
            "type": "string",
            "nullable": true
          },
          "hasBeenLiquidated": {
            "type": "boolean"
          },
          "lastAccountsMadeUpToActual": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "lastAccountsType": {
            "type": "string",
            "nullable": true
          },
          "confirmationStatementLastMadeUpTo": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "accountsOverdue": {
            "type": "boolean"
          },
          "confirmationStatementOverdue": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "CompanyAddress": {
        "type": "object",
        "properties": {
          "addressLine1": {
            "type": "string",
            "nullable": true
          },
          "addressLine2": {
            "type": "string",
            "nullable": true
          },
          "locality": {
            "type": "string",
            "nullable": true
          },
          "premises": {
            "type": "string",
            "nullable": true
          },
          "postalCode": {
            "type": "string",
            "nullable": true
          },
          "country": {
            "type": "string",
            "nullable": true
          },
          "region": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CompanyDetailsDto": {
        "type": "object",
        "properties": {
          "number": {
            "maxLength": 50,
            "type": "string",
            "description": "UK Companies House registration number",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/CompanyStatus"
          },
          "incorporationDate": {
            "type": "string",
            "description": "Date the company was incorporated/registered with Companies House",
            "format": "date-time",
            "nullable": true
          },
          "registeredAddress": {
            "maxLength": 500,
            "type": "string",
            "description": "Official registered office address as filed with Companies House",
            "nullable": true
          },
          "sicCodes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CodeAndNameDto"
            },
            "description": "Standard Industrial Classification codes describing the company's business activities",
            "nullable": true
          },
          "authenticationCode": {
            "maxLength": 100,
            "type": "string",
            "description": "Authentication code required for filing with Companies House",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Company registration and filing details (Companies House)"
      },
      "CompanySearchResponse": {
        "type": "object",
        "properties": {
          "totalResults": {
            "type": "integer",
            "format": "int32"
          },
          "itemsPerPage": {
            "type": "integer",
            "format": "int32"
          },
          "startIndex": {
            "type": "integer",
            "format": "int32"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CompanySearchResult"
            },
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CompanySearchResult": {
        "type": "object",
        "properties": {
          "companyNumber": {
            "type": "string",
            "nullable": true
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "companyStatus": {
            "type": "string",
            "nullable": true
          },
          "companyType": {
            "type": "string",
            "nullable": true
          },
          "dateOfCreation": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "address": {
            "$ref": "#/components/schemas/CompanyAddress"
          },
          "matchedPreviousCompanyNames": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CompanyStatus": {
        "enum": [
          "Active",
          "Dissolved",
          "Dormant",
          "ProposalToStrikeOff",
          "Liquidation",
          "VoluntaryArrangement",
          "Administration",
          "ConvertedClosed",
          "Receivership",
          "InsolvencyProceedings",
          "Open",
          "Closed"
        ],
        "type": "string"
      },
      "CompleteMandateSetupRequest": {
        "required": [
          "redirectFlowId"
        ],
        "type": "object",
        "properties": {
          "redirectFlowId": {
            "minLength": 1,
            "type": "string",
            "description": "The redirect flow ID returned by GoCardless in the callback URL query string."
          }
        },
        "additionalProperties": false,
        "description": "Request model for completing a GoCardless Direct Debit mandate setup\nafter the user has authorised the mandate."
      },
      "ConditionDto": {
        "type": "object",
        "properties": {
          "sourceType": {
            "$ref": "#/components/schemas/ConditionSourceType"
          },
          "questionCode": {
            "type": "string",
            "description": "When SourceType is FormQuestion: the code of the question whose answer is compared.\nOnly valid on data form sections/questions.",
            "nullable": true
          },
          "clientField": {
            "$ref": "#/components/schemas/ClientCsvTargetField"
          },
          "customFieldDefinition": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "showWhenIs": {
            "type": "string",
            "description": "The value the condition source must have for the item to be visible/included.\nFor booleans: \"true\" or \"false\". For dropdowns: the selected option value.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A conditional-visibility rule shared by data form sections/questions and workflow\ngroups/steps: the item is only shown/included when the referenced field has the\nShowWhenIs value. Null (no condition object) means the item is always shown."
      },
      "ConditionSourceType": {
        "enum": [
          "FormQuestion",
          "ClientField",
          "CustomField"
        ],
        "type": "string"
      },
      "ConfigurationStatus": {
        "enum": [
          "PendingOAuthSetup",
          "Active",
          "OAuthFailed",
          "Deleted",
          "OAuthExpired",
          "ConnectionError",
          "Deleting"
        ],
        "type": "string",
        "description": "Represents the lifecycle status of an email configuration"
      },
      "ConfirmCsvImportRequest": {
        "type": "object",
        "properties": {
          "mappingCode": {
            "type": "string",
            "description": "Code of an existing saved mapping to use for this import.\nUse GET /mappings to list available mappings (includes system defaults like 'limited-company-clients').\nMutually exclusive with ColumnMappings - provide one or the other, not both.\nIf neither is provided, the suggested mappings from the preview will be used.",
            "nullable": true,
            "example": "limited-company-clients"
          },
          "columnMappings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CsvColumnMappingDto"
            },
            "description": "Inline column mappings to use for this import.\nEach mapping specifies which CSV header maps to which target field.\nMutually exclusive with MappingCode - provide one or the other, not both.\nIf neither is provided, the suggested mappings from the preview will be used.",
            "nullable": true
          },
          "matchField": {
            "$ref": "#/components/schemas/CsvImportMatchField"
          },
          "importMode": {
            "$ref": "#/components/schemas/CsvImportMode"
          },
          "enrichFromCompaniesHouse": {
            "type": "boolean",
            "description": "Whether to enrich newly created clients with Companies House data after import.\nOnly applies to eligible company types (excludes Individual, SoleTrader, Trust).\nDefault: false",
            "example": true
          },
          "defaultClientType": {
            "$ref": "#/components/schemas/ClientType"
          }
        },
        "additionalProperties": false,
        "description": "Request to confirm column mapping configuration and start a CSV import job.\nUsed after uploading a CSV with showPreview=true to finalize the mapping and begin import."
      },
      "ConnectionCredentialsResponse": {
        "type": "object",
        "properties": {
          "accessToken": {
            "type": "string",
            "description": "The OAuth access token",
            "nullable": true
          },
          "clientId": {
            "type": "string",
            "description": "The OAuth client ID",
            "nullable": true
          },
          "baseUrl": {
            "type": "string",
            "description": "The SharePoint/OneDrive base URL for the file picker",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response containing OAuth credentials for a connection"
      },
      "ConnectionFolderDto": {
        "type": "object",
        "properties": {
          "containerId": {
            "type": "string",
            "description": "Platform-specific folder identifier. Pass this back as `parentFolderId` to drill in.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Folder display name.",
            "nullable": true
          },
          "webUrl": {
            "type": "string",
            "description": "Direct link to open the folder in the provider's web UI.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A folder available in a document storage connection. Returned by the list-folders endpoint\nused to drive the in-app folder browser."
      },
      "ConnectionStatus": {
        "enum": [
          "NotInitiated",
          "Initialising",
          "Active",
          "Expired",
          "Revoked",
          "Error"
        ],
        "type": "string"
      },
      "ContactDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this contact",
            "nullable": true
          },
          "title": {
            "type": "string",
            "description": "The contact's title (e.g., Mr, Mrs, Dr)",
            "nullable": true
          },
          "firstName": {
            "type": "string",
            "description": "The contact's first name",
            "nullable": true
          },
          "middleName": {
            "type": "string",
            "description": "The contact's middle name",
            "nullable": true
          },
          "lastName": {
            "type": "string",
            "description": "The contact's last name",
            "nullable": true
          },
          "email": {
            "type": "string",
            "description": "The contact's email address",
            "nullable": true
          },
          "phone": {
            "type": "string",
            "description": "The contact's phone number",
            "nullable": true
          },
          "mobile": {
            "type": "string",
            "description": "The contact's mobile number",
            "nullable": true
          },
          "dateOfBirth": {
            "type": "string",
            "description": "The contact's date of birth",
            "format": "date",
            "nullable": true
          },
          "utr": {
            "type": "string",
            "description": "The contact's Unique Taxpayer Reference (Self Assessment UTR).\nUsed for individuals' personal tax affairs.",
            "nullable": true
          },
          "niNumber": {
            "type": "string",
            "description": "The contact's National Insurance Number.",
            "nullable": true
          },
          "personalCode": {
            "type": "string",
            "description": "The contact's Companies House person ID code, used to uniquely identify\nan individual within the Companies House system.",
            "nullable": true
          },
          "address": {
            "type": "string",
            "description": "The contact's address. Only used when the client type is Individual.",
            "nullable": true
          },
          "nationality": {
            "$ref": "#/components/schemas/Nationality"
          },
          "maritalStatus": {
            "$ref": "#/components/schemas/MaritalStatus"
          },
          "isDeceased": {
            "type": "boolean",
            "description": "Whether this contact is deceased"
          },
          "deceasedDate": {
            "type": "string",
            "description": "The date the contact was deceased, if known",
            "format": "date",
            "nullable": true
          },
          "clientCount": {
            "type": "integer",
            "description": "The number of clients this contact is associated with.",
            "format": "int32"
          },
          "client": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "portalUser": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "individualClient": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          }
        },
        "additionalProperties": false,
        "description": "Represents a person or contact within the tenant's organization.\nContacts can be associated with one or more clients and contain contact details such as name, email, and phone numbers."
      },
      "ContactDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ContactDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "ContactPreferencesDto": {
        "type": "object",
        "properties": {
          "post": {
            "type": "boolean",
            "description": "Whether the client can be contacted by post"
          },
          "telephone": {
            "type": "boolean",
            "description": "Whether the client can be contacted by telephone"
          },
          "email": {
            "type": "boolean",
            "description": "Whether the client can be contacted by email"
          },
          "sms": {
            "type": "boolean",
            "description": "Whether the client can be contacted by SMS"
          }
        },
        "additionalProperties": false,
        "description": "Contact preferences for a client"
      },
      "ContactSortField": {
        "enum": [
          "Name",
          "FirstName",
          "LastName",
          "ClientCount"
        ],
        "type": "string"
      },
      "ContentBlockCategory": {
        "enum": [
          "Custom",
          "ServiceTerms",
          "ServiceProposals",
          "TemplateParts",
          "WebContent",
          "Email",
          "EmailParts"
        ],
        "type": "string"
      },
      "ContentBlockCollection": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ContentBlockReference"
            },
            "description": "List of content block references with their variables.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Collection of content block references.\nGeneric wrapper that can be reused for any list of content blocks (schedules, sections, etc.)."
      },
      "ContentBlockDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Stable identifier. For library-shipped items this is the library code; for tenant-imported\nitems this is the tenant entity's own code.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name shown to users in lists, dialogs, and the import browser.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Optional human-readable summary of what this entity is for.",
            "nullable": true
          },
          "libraryCode": {
            "type": "string",
            "description": "The Code of the library template this entity was imported from, or null if the entity\nis not from the library. Read-only — cannot be changed once set. Example: \"vat_returns\".",
            "nullable": true
          },
          "libraryStatus": {
            "$ref": "#/components/schemas/LibraryStatus"
          },
          "isImported": {
            "type": "boolean",
            "description": "True if the tenant has already imported this library item."
          },
          "deprecated": {
            "type": "boolean",
            "description": "True if this library item has been retired. Deprecated items are hidden from the import\nbrowser (so new tasks cannot be created from them) but remain available for revert-to-library\non existing imports."
          },
          "bodyHtml": {
            "type": "string",
            "nullable": true
          },
          "category": {
            "$ref": "#/components/schemas/ContentBlockCategory"
          },
          "subjectLine": {
            "type": "string",
            "description": "Optional subject line for email content blocks (only relevant when Category is EmailParts).\nSupports merge field syntax (e.g., {{ Client.Name }}).",
            "nullable": true
          },
          "hasClientTokens": {
            "type": "boolean",
            "description": "Whether any field (SubjectLine or BodyHtml) contains {{ Client.* }} Liquid tokens.\nUse to determine if a content block requires a client context for rendering."
          },
          "createdDate": {
            "type": "string",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "DTO for content blocks, exposing only codes and structured data (never DB IDs)."
      },
      "ContentBlockDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ContentBlockDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "ContentBlockReference": {
        "type": "object",
        "properties": {
          "contentBlock": {
            "type": "string",
            "description": "The code of the content block to render.",
            "nullable": true
          },
          "vars": {
            "type": "object",
            "additionalProperties": {
              "nullable": true
            },
            "description": "Variables to pass to the content block template.\nThese become available in the content block's template context.\nExample: { \"price\": 1000, \"billingFrequency\": \"Monthly\" }",
            "nullable": true
          },
          "meta": {
            "description": "Optional metadata for additional context (not passed to template).\nCan be used for conditional logic or tracking purposes.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Generic container for passing dynamic content blocks with variables and metadata to templates.\nThis allows templates to render content blocks with additional context (e.g., price, frequency)."
      },
      "ContentBlockSortField": {
        "enum": [
          "Name",
          "Category",
          "UpdatedDate"
        ],
        "type": "string"
      },
      "ConversationClientAssociationDto": {
        "type": "object",
        "properties": {
          "clientCode": {
            "type": "string",
            "description": "The client's code",
            "nullable": true
          },
          "clientName": {
            "type": "string",
            "description": "The client's name",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A client associated with a conversation"
      },
      "ConversationClientSuggestionDto": {
        "type": "object",
        "properties": {
          "clientCode": {
            "type": "string",
            "description": "The client's code",
            "nullable": true
          },
          "clientName": {
            "type": "string",
            "description": "The client's name",
            "nullable": true
          },
          "matchedEmail": {
            "type": "string",
            "description": "The email address that matched (from a contact or the client itself)",
            "nullable": true
          },
          "matchedVia": {
            "type": "string",
            "description": "Where the match was found: \"client\" (the client's own email) or the contact's name",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A suggested client to associate with a conversation, based on matching participant emails"
      },
      "ConversationWithAssociationsDto": {
        "type": "object",
        "properties": {
          "messages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ExternalMailboxEmailSummaryDto"
            },
            "description": "The messages in this conversation, ordered by date",
            "nullable": true
          },
          "clientAssociations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConversationClientAssociationDto"
            },
            "description": "Clients associated with this conversation based on participant email addresses matching client email rules.\nEmpty if no participants match any rules.",
            "nullable": true
          },
          "suggestedClients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConversationClientSuggestionDto"
            },
            "description": "Suggested clients to associate with this conversation, based on participant email addresses\nmatching client or contact email addresses. Only populated when there are no existing associations.",
            "nullable": true
          },
          "participantEmails": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The unique participant email addresses from this conversation's messages.\nUseful for creating association rules from the frontend.",
            "nullable": true
          },
          "taskAssociations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CodeAndNameDto"
            },
            "description": "Tasks explicitly linked to this conversation by users.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A conversation's messages enriched with client associations derived from email rules."
      },
      "ConvertFieldWarningType": {
        "enum": [
          "UnsupportedClientField",
          "UnknownCustomField"
        ],
        "type": "string",
        "description": "Types of conversion warnings"
      },
      "ConvertFormFieldWarning": {
        "type": "object",
        "properties": {
          "formName": {
            "type": "string",
            "description": "The name of the form containing the unmapped field",
            "nullable": true
          },
          "sectionTitle": {
            "type": "string",
            "description": "The section title containing the unmapped field",
            "nullable": true
          },
          "questionLabel": {
            "type": "string",
            "description": "The question label/prompt",
            "nullable": true
          },
          "originalField": {
            "type": "string",
            "description": "The original field identifier from the source system",
            "nullable": true
          },
          "warningType": {
            "$ref": "#/components/schemas/ConvertFieldWarningType"
          }
        },
        "additionalProperties": false,
        "description": "A warning about a field that could not be automatically mapped during conversion"
      },
      "ConvertFormFileRequest": {
        "type": "object",
        "properties": {
          "content": {
            "type": "string",
            "description": "The raw file content (e.g. a CEXP-V1 export file)",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request to convert an external form definition file into the Sodium import format.\nThe raw file content is posted as the request body (text/plain)."
      },
      "ConvertFormFileResponse": {
        "type": "object",
        "properties": {
          "forms": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CreateDataFormRequest"
            },
            "description": "The converted forms in Sodium's CreateDataFormRequest format, ready for import",
            "nullable": true
          },
          "warnings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConvertFormFieldWarning"
            },
            "description": "Warnings about fields that could not be automatically mapped (e.g. unrecognised custom fields, unsupported builtin fields)",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Result of converting an external form definition file into the Sodium import format"
      },
      "CreateAmlClientRequest": {
        "required": [
          "clientCode",
          "contacts",
          "name"
        ],
        "type": "object",
        "properties": {
          "clientCode": {
            "minLength": 1,
            "type": "string"
          },
          "externalReference": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "minLength": 1,
            "type": "string"
          },
          "isIndividual": {
            "type": "boolean"
          },
          "regNumber": {
            "type": "string",
            "nullable": true
          },
          "contacts": {
            "minItems": 1,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CreateAmlContactRequest"
            }
          }
        },
        "additionalProperties": false
      },
      "CreateAmlContactRequest": {
        "required": [
          "email",
          "firstName",
          "lastName"
        ],
        "type": "object",
        "properties": {
          "contactCode": {
            "type": "string",
            "description": "The Sodium client-contact code. Used to store the AML contact ID back after creation.",
            "nullable": true
          },
          "firstName": {
            "minLength": 1,
            "type": "string"
          },
          "lastName": {
            "minLength": 1,
            "type": "string"
          },
          "email": {
            "minLength": 1,
            "type": "string",
            "format": "email"
          },
          "phone": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CreateApiKeyRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The friendly name for this API key",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request to create a new API key"
      },
      "CreateBillableServiceRequest": {
        "required": [
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "minLength": 1,
            "type": "string",
            "description": "The name of the service"
          },
          "description": {
            "type": "string",
            "description": "The description of the service",
            "nullable": true
          },
          "clientTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientType"
            },
            "description": "The types of clients this service is applicable to.\nAn empty list means the service is applicable to all client types.",
            "nullable": true
          },
          "agentAuthorisations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AgentAuthorisationType"
            },
            "description": "The HMRC agent authorisation types relevant to this service",
            "nullable": true
          },
          "isArchived": {
            "type": "boolean",
            "description": "Indicates whether this service is archived (inactive)"
          },
          "accountingCode": {
            "maxLength": 20,
            "minLength": 0,
            "type": "string",
            "description": "The accounting code for this service (max 20 characters)",
            "nullable": true
          },
          "defaultManagedByUserCode": {
            "type": "string",
            "description": "The code of the user who is the default manager for this service",
            "nullable": true
          },
          "serviceScheduleContentCode": {
            "type": "string",
            "description": "The code of the content block to use for service schedule",
            "nullable": true
          },
          "proposalContentCode": {
            "type": "string",
            "description": "The code of the content block to use for proposals",
            "nullable": true
          },
          "category": {
            "$ref": "#/components/schemas/ServiceCategory"
          },
          "vatRate": {
            "$ref": "#/components/schemas/VatRate"
          },
          "pricingMode": {
            "$ref": "#/components/schemas/ServicePricingMode"
          },
          "pricingTiers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BillableServicePricingTierDto"
            },
            "description": "Custom pricing tiers. Required when PricingMode = CustomTiers.",
            "nullable": true
          },
          "showKanbanBoard": {
            "type": "boolean",
            "description": "Whether this service should appear on the Boards kanban view"
          },
          "stages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BillableServiceStageDto"
            },
            "description": "User-defined workflow stages for this service",
            "nullable": true
          },
          "pricing": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BillableServicePricingOptionDto"
            },
            "description": "The pricing options for this service",
            "nullable": true
          },
          "pricingFactors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PricingFactorDto"
            },
            "description": "The pricing factors that can affect the service pricing calculations",
            "nullable": true
          },
          "pcrItemCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The codes of professional clearance request items for this service",
            "nullable": true
          },
          "invoiceLineDescriptionTemplate": {
            "maxLength": 500,
            "minLength": 0,
            "type": "string",
            "description": "Smart name token template for invoice line descriptions (e.g. \"{{ ServiceName }} - {{ Month }} {{ Year }}\")",
            "nullable": true
          },
          "setupFee": {
            "minimum": 0,
            "type": "number",
            "description": "Optional one-off setup fee charged when the service is first billed for a client.\nNull means no setup fee.",
            "format": "double",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for creating a new billable service"
      },
      "CreateClientBillableServiceRequest": {
        "required": [
          "billableServiceCode",
          "billingFrequency",
          "startDate"
        ],
        "type": "object",
        "properties": {
          "billableServiceCode": {
            "minLength": 1,
            "type": "string",
            "description": "The code of the billable service to assign to this client"
          },
          "billingFrequency": {
            "$ref": "#/components/schemas/BillingFrequency"
          },
          "price": {
            "minimum": 0,
            "type": "number",
            "description": "The base price for this client's service (before any adjustment).\nThe final price is: Price + (Price * PriceAdjustmentPercentage / 100) + PriceAdjustmentFixedAmount.\nRequired when OverridePricing = true; ignored when OverridePricing = false (price comes from BillableService).",
            "format": "double",
            "nullable": true
          },
          "overridePricing": {
            "type": "boolean",
            "description": "Indicates whether to use a custom Price value instead of BillableService pricing\nIf true: Must provide Price value\nIf false: Price is loaded from BillableService, and the client-level adjustment is applied"
          },
          "priceAdjustmentPercentage": {
            "type": "number",
            "description": "Percentage contribution from selected Percentage-mode pricing factors (positive or negative). Use -10 for 10% discount, 20 for 20% markup. Defaults to 0.",
            "format": "double"
          },
          "priceAdjustmentFixedAmount": {
            "type": "number",
            "description": "Absolute currency contribution from selected FixedAmount-mode pricing factors (positive or negative). Defaults to 0.",
            "format": "double"
          },
          "startDate": {
            "type": "string",
            "description": "The start date for this service",
            "format": "date-time"
          },
          "endDate": {
            "type": "string",
            "description": "The end date for this service (optional - null means ongoing)",
            "format": "date-time",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/ServiceStatus"
          },
          "managedByUserCode": {
            "type": "string",
            "description": "The code of the user managing this service",
            "nullable": true
          },
          "pricingAnswers": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "The pricing factor answers that determined the final price\nKey: Question, Value: Answer",
            "nullable": true
          },
          "pricingTierCode": {
            "type": "string",
            "description": "The code of the custom pricing tier to apply. Required when the BillableService uses CustomTiers and OverridePricing = false.",
            "nullable": true
          },
          "stageCode": {
            "type": "string",
            "description": "The code of the current workflow stage to set on this service (optional)",
            "nullable": true
          },
          "servicePackageCode": {
            "type": "string",
            "description": "The code of the service package this service was created from, if any.\nLinks the service to its originating package for display and pricing purposes.",
            "nullable": true
          },
          "setupFee": {
            "minimum": 0,
            "type": "number",
            "description": "The one-off setup fee for this client's service. Null means no setup fee.\nWhen OverrideSetupFee = false, pass the BillableService.SetupFee default (or null).\nWhen OverrideSetupFee = true, pass the custom fee (null/0 removes the fee for this client).",
            "format": "double",
            "nullable": true
          },
          "overrideSetupFee": {
            "type": "boolean",
            "description": "Indicates whether to use a custom SetupFee value instead of the BillableService default"
          },
          "autoInvoice": {
            "type": "boolean",
            "description": "Whether this service should automatically generate invoice line items"
          },
          "nextBillingDate": {
            "type": "string",
            "description": "The next date a billable line item should be generated. When omitted and AutoInvoice = true,\ndefaults to StartDate advanced by one BillingFrequency period.",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for creating a new client billable service assignment"
      },
      "CreateClientBillingLineItemRequest": {
        "required": [
          "billingDate",
          "description",
          "unitPrice"
        ],
        "type": "object",
        "properties": {
          "clientBillableServiceCode": {
            "type": "string",
            "description": "The code of the client billable service to link this line item to (optional)",
            "nullable": true
          },
          "description": {
            "maxLength": 500,
            "minLength": 1,
            "type": "string",
            "description": "The invoice line description"
          },
          "quantity": {
            "type": "number",
            "description": "The quantity (defaults to 1)",
            "format": "double"
          },
          "unitPrice": {
            "type": "number",
            "description": "The unit price",
            "format": "double"
          },
          "vatRate": {
            "$ref": "#/components/schemas/VatRate"
          },
          "accountingCode": {
            "maxLength": 20,
            "type": "string",
            "description": "The accounting/nominal code (optional)",
            "nullable": true
          },
          "periodStart": {
            "type": "string",
            "description": "Start of the service period covered (optional)",
            "format": "date-time",
            "nullable": true
          },
          "periodEnd": {
            "type": "string",
            "description": "End of the service period covered (optional)",
            "format": "date-time",
            "nullable": true
          },
          "billingDate": {
            "type": "string",
            "description": "Target invoice date",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "Request to manually create a billing line item for a client"
      },
      "CreateClientContactRequest": {
        "required": [
          "types"
        ],
        "type": "object",
        "properties": {
          "role": {
            "type": "string",
            "description": "The role of the contact within this client relationship",
            "nullable": true
          },
          "types": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientContactType"
            },
            "description": "The type of contact relationship"
          },
          "contact": {
            "$ref": "#/components/schemas/ContactDto"
          },
          "resignedDate": {
            "type": "string",
            "description": "Date the contact resigned their officer role for this client. Usually populated by the\nCompanies House officer stream; user-editable so it can also be set manually (or cleared).",
            "format": "date",
            "nullable": true
          },
          "ceasedDate": {
            "type": "string",
            "description": "Date the contact ceased being a Person with Significant Control for this client. Usually\npopulated by the Companies House PSC stream; user-editable so it can also be set manually.",
            "format": "date",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for creating a new client-contact relationship"
      },
      "CreateClientDocumentFromTemplateRequest": {
        "required": [
          "templateCode",
          "title"
        ],
        "type": "object",
        "properties": {
          "templateCode": {
            "minLength": 1,
            "type": "string",
            "description": "Code of the document template to render."
          },
          "designThemeCode": {
            "type": "string",
            "description": "Optional design theme code. If not specified, the template's default or tenant default is used.",
            "nullable": true
          },
          "title": {
            "maxLength": 200,
            "minLength": 1,
            "type": "string",
            "description": "Title for the generated document."
          },
          "summary": {
            "maxLength": 2000,
            "type": "string",
            "description": "Optional summary/description for the generated document.",
            "nullable": true
          },
          "documentCategoryCode": {
            "type": "string",
            "description": "Optional document category code.",
            "nullable": true
          },
          "customTokens": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Custom token values to inject into the template. Keys are token names, values are the text to substitute.\nAccessible in templates as {{ CustomFields.TokenName }}.",
            "nullable": true
          },
          "visibleInClientPortal": {
            "type": "boolean",
            "description": "Whether the generated document should be visible in the client portal. Defaults to true."
          },
          "portalFolderPath": {
            "type": "string",
            "description": "Portal folder path for the generated document. Defaults to \"Generated Documents\" if not specified.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request to generate a PDF document from a template and save it as a client document."
      },
      "CreateClientEmailRuleRequest": {
        "required": [
          "value"
        ],
        "type": "object",
        "properties": {
          "value": {
            "maxLength": 255,
            "minLength": 0,
            "type": "string",
            "description": "The email address, domain, or message ID to match.\nEmail addresses (contain '@') match that specific participant.\nDomains (no '@', not a GUID) match all emails from that domain.\nMessage IDs (valid GUID) pin a specific email to this client."
          }
        },
        "additionalProperties": false,
        "description": "Request to create a new email rule for a client.\nProvide an email address (e.g. \"john@acme.com\") to match that participant,\na domain (e.g. \"acme.com\") to match all emails from that domain,\nor a message ID (GUID) to pin a specific email to this client."
      },
      "CreateClientLinkRequest": {
        "required": [
          "linkType",
          "url"
        ],
        "type": "object",
        "properties": {
          "url": {
            "minLength": 1,
            "type": "string",
            "description": "The URL of the link",
            "format": "uri"
          },
          "linkType": {
            "$ref": "#/components/schemas/LinkType"
          },
          "displayName": {
            "maxLength": 200,
            "type": "string",
            "description": "Optional display name shown as anchor text instead of the URL",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for creating a new client link"
      },
      "CreateClientNoteRequest": {
        "required": [
          "date",
          "text"
        ],
        "type": "object",
        "properties": {
          "text": {
            "minLength": 1,
            "type": "string",
            "description": "The text content of the note"
          },
          "date": {
            "type": "string",
            "description": "The date/time the note was created",
            "format": "date-time"
          },
          "noteFromUserCode": {
            "type": "string",
            "description": "The code of the user who authored this note. Defaults to the authenticated user if not provided.",
            "nullable": true
          },
          "pinnedLevel": {
            "type": "integer",
            "description": "The pinned level for ordering pinned notes",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for creating a new client note"
      },
      "CreateClientPipelineRequest": {
        "required": [
          "pipelineCode",
          "startDate"
        ],
        "type": "object",
        "properties": {
          "pipelineCode": {
            "minLength": 1,
            "type": "string",
            "description": "The code of the pipeline to place the client on"
          },
          "stageCode": {
            "type": "string",
            "description": "The code of the initial stage (optional — null means no stage yet)",
            "nullable": true
          },
          "managedByUserCode": {
            "type": "string",
            "description": "The code of the user managing this card (optional)",
            "nullable": true
          },
          "startDate": {
            "type": "string",
            "description": "The date the client entered the pipeline",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for placing a client on a sales pipeline (creating a card)"
      },
      "CreateClientRequest": {
        "required": [
          "name",
          "type"
        ],
        "type": "object",
        "properties": {
          "name": {
            "minLength": 1,
            "type": "string",
            "description": "The name of the client"
          },
          "type": {
            "$ref": "#/components/schemas/ClientType"
          },
          "internalReference": {
            "type": "string",
            "description": "Optional internal reference number/code for the client",
            "nullable": true
          },
          "managerCode": {
            "type": "string",
            "description": "Code of the user who will manage this client.\nThe user must exist and have access to the tenant.",
            "nullable": true
          },
          "partnerCode": {
            "type": "string",
            "description": "Code of the user who will be the partner for this client.\nThe user must exist and have access to the tenant.",
            "nullable": true
          },
          "associateCode": {
            "type": "string",
            "description": "Code of the user who will be the associate for this client.\nThe user must exist and have access to the tenant.",
            "nullable": true
          },
          "teamCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Codes of teams to assign to this client",
            "nullable": true
          },
          "revenueRangeCode": {
            "type": "string",
            "description": "The revenue range code for this client",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/ClientStatus"
          },
          "accountingCustomerCode": {
            "type": "string",
            "description": "The customer code/ID from the connected accounting platform",
            "nullable": true
          },
          "directDebitMandateId": {
            "type": "string",
            "description": "The mandate ID from the connected direct debit platform",
            "nullable": true
          },
          "amlClientId": {
            "type": "string",
            "description": "The client/account ID from the connected AML platform",
            "nullable": true
          },
          "amlClientName": {
            "type": "string",
            "description": "The display name of the client in the connected AML platform",
            "nullable": true
          },
          "email": {
            "type": "string",
            "description": "The email address for the client",
            "nullable": true
          },
          "telephone": {
            "type": "string",
            "description": "The telephone number for the client",
            "nullable": true
          },
          "contactPreferences": {
            "$ref": "#/components/schemas/ContactPreferencesDto"
          },
          "invoiceDayOfMonth": {
            "type": "integer",
            "description": "Day of month (1-28) for automatic invoicing. Null disables auto-invoicing.",
            "format": "int32",
            "nullable": true
          },
          "invoicePaymentTermDays": {
            "type": "integer",
            "description": "Payment terms in days for generated invoices",
            "format": "int32",
            "nullable": true
          },
          "lineItemApprovalRequired": {
            "type": "boolean",
            "description": "Null = use tenant default. True = require manual approval. False = auto-approve.",
            "nullable": true
          },
          "pclSent": {
            "type": "boolean",
            "description": "Indicates whether a Professional Clearance Letter has been sent for this client"
          },
          "snoozeChasesUntil": {
            "type": "string",
            "description": "Suppresses automated chase emails for this client until this date (chasing resumes on the date itself).\nNull = chases are not snoozed.",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for creating a new client"
      },
      "CreateContactRequest": {
        "type": "object",
        "properties": {
          "title": {
            "maxLength": 20,
            "type": "string",
            "description": "The contact's title (e.g., Mr, Mrs, Ms, Dr)",
            "nullable": true
          },
          "firstName": {
            "maxLength": 100,
            "type": "string",
            "description": "The contact's first name",
            "nullable": true
          },
          "middleName": {
            "maxLength": 100,
            "type": "string",
            "description": "The contact's middle name",
            "nullable": true
          },
          "lastName": {
            "maxLength": 100,
            "type": "string",
            "description": "The contact's last name",
            "nullable": true
          },
          "email": {
            "maxLength": 200,
            "type": "string",
            "description": "The contact's email address",
            "nullable": true
          },
          "phone": {
            "maxLength": 50,
            "type": "string",
            "description": "The contact's landline phone number",
            "nullable": true
          },
          "mobile": {
            "maxLength": 50,
            "type": "string",
            "description": "The contact's mobile phone number",
            "nullable": true
          },
          "dateOfBirth": {
            "type": "string",
            "description": "The contact's date of birth",
            "format": "date",
            "nullable": true
          },
          "utr": {
            "type": "string",
            "description": "The contact's Unique Taxpayer Reference (Self Assessment UTR).\nUsed for individuals' personal tax affairs.",
            "nullable": true
          },
          "niNumber": {
            "type": "string",
            "description": "The contact's National Insurance Number.",
            "nullable": true
          },
          "personalCode": {
            "maxLength": 50,
            "type": "string",
            "description": "The contact's Companies House person ID code, used to uniquely identify\nan individual within the Companies House system.",
            "nullable": true
          },
          "address": {
            "type": "string",
            "description": "The contact's address. Only used when the client type is Individual.",
            "nullable": true
          },
          "nationality": {
            "$ref": "#/components/schemas/Nationality"
          },
          "maritalStatus": {
            "$ref": "#/components/schemas/MaritalStatus"
          },
          "isDeceased": {
            "type": "boolean",
            "description": "Whether this contact is deceased"
          },
          "deceasedDate": {
            "type": "string",
            "description": "The date the contact was deceased, if known",
            "format": "date",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "DTO for creating a contact"
      },
      "CreateContentBlockRequest": {
        "required": [
          "category",
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "maxLength": 200,
            "minLength": 0,
            "type": "string",
            "description": "Display name for the content block (e.g., \"Standard Header\", \"Legal Footer\", \"Signature Block\")"
          },
          "bodyHtml": {
            "type": "string",
            "description": "HTML content of the block with Liquid syntax support.\nContent blocks receive the same token context as the parent template, allowing them to access:\n- All data passed to the template (client, services, custom fields)\n- System-provided tokens (tenant, date)\n- Nested content blocks using {{ contentBlock \"another-block\" }}\n\nExample header block:\n\n<header>\n  <h1>{{ tenant.name }}</h1>\n  <p>{{ tenant.address.line1 }}, {{ tenant.address.city }}</p>\n  <p>Date: {{ date | date: \"%B %d, %Y\" }}</p>\n</header>\n\n\nExample conditional footer:\n\n<footer>\n  {% if client.isVatRegistered %}\n  <p>VAT Number: {{ client.vatNumber }}</p>\n  {% endif %}\n  <p>© {{ date | date: \"%Y\" }} {{ tenant.name }}</p>\n</footer>",
            "nullable": true
          },
          "description": {
            "maxLength": 500,
            "minLength": 0,
            "type": "string",
            "description": "Optional description explaining the block's purpose and where it should be used",
            "nullable": true
          },
          "category": {
            "$ref": "#/components/schemas/ContentBlockCategory"
          },
          "subjectLine": {
            "maxLength": 500,
            "minLength": 0,
            "type": "string",
            "description": "Optional subject line for email content blocks (only relevant when Category is EmailParts).\nSupports merge field syntax (e.g., {{ Client.Name }}).",
            "nullable": true
          },
          "libraryCode": {
            "maxLength": 100,
            "minLength": 0,
            "type": "string",
            "description": "Optional reference to the library item code this content block was imported from.\nUsed to track the origin of content blocks created from the library.\nCan only be set during creation and cannot be modified later.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request to create a new reusable content block that can be included in document templates.\nContent blocks are shared sections of content that maintain consistency across documents."
      },
      "CreateCsvMappingRequest": {
        "required": [
          "columnMappings",
          "mappingType",
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "minLength": 1,
            "type": "string",
            "description": "Human-readable display name for this mapping.\nChoose a descriptive name that identifies the CSV format (e.g., 'IRIS Export', 'Xero Contacts').\nRequired.",
            "example": "IRIS Client Export"
          },
          "columnMappings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CsvColumnMappingDto"
            },
            "description": "The column mappings that define how CSV headers map to client fields.\nEach mapping specifies a CSV header and the corresponding target field.\nRequired - must include at least one mapping."
          },
          "matchField": {
            "$ref": "#/components/schemas/CsvImportMatchField"
          },
          "mappingType": {
            "$ref": "#/components/schemas/CsvMappingType"
          }
        },
        "additionalProperties": false,
        "description": "Request to create a new reusable CSV mapping.\nSaved mappings can be referenced by code in future imports/exports,\neliminating the need to specify column mappings each time."
      },
      "CreateCustomFieldDefinitionRequest": {
        "required": [
          "customFieldGroupCode"
        ],
        "type": "object",
        "properties": {
          "label": {
            "type": "string",
            "nullable": true
          },
          "entityType": {
            "$ref": "#/components/schemas/CustomFieldEntityType"
          },
          "dataType": {
            "$ref": "#/components/schemas/CustomFieldDataType"
          },
          "options": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          },
          "maxLength": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "lines": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "displayWidth": {
            "$ref": "#/components/schemas/FieldDisplayWidth"
          },
          "booleanDisplayMode": {
            "$ref": "#/components/schemas/BooleanDisplayMode"
          },
          "clientTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientType"
            },
            "description": "The types of clients this custom field is applicable to.\nAn empty list means the field is applicable to all client types.",
            "nullable": true
          },
          "customFieldGroupCode": {
            "minLength": 1,
            "type": "string"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          }
        },
        "additionalProperties": false
      },
      "CreateCustomFieldGroupRequest": {
        "required": [
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "maxLength": 200,
            "minLength": 1,
            "type": "string"
          },
          "entityType": {
            "$ref": "#/components/schemas/CustomFieldEntityType"
          },
          "parentCustomFieldGroupCode": {
            "type": "string",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          }
        },
        "additionalProperties": false
      },
      "CreateCustomTokenRequest": {
        "required": [
          "name",
          "tokenIdentifier"
        ],
        "type": "object",
        "properties": {
          "name": {
            "maxLength": 120,
            "minLength": 1,
            "type": "string",
            "description": "Human-readable display name for the token (e.g. \"Company Secretary\")"
          },
          "tokenIdentifier": {
            "maxLength": 120,
            "minLength": 1,
            "type": "string",
            "description": "The token identifier used in templates (e.g. \"CompanySecretary\" for {{ Custom.CompanySecretary }}).\nMust be alphanumeric with underscores only. Unique per tenant."
          },
          "description": {
            "maxLength": 500,
            "type": "string",
            "description": "Optional prompt text shown when filling in the token value",
            "nullable": true
          },
          "defaultValue": {
            "maxLength": 500,
            "type": "string",
            "description": "Optional default value pre-populated in the token form",
            "nullable": true
          },
          "displayWidth": {
            "type": "string",
            "description": "Preset display width for the input. Null defaults to Full.",
            "nullable": true
          },
          "lines": {
            "type": "integer",
            "description": "Number of visible text lines. Null renders a single-line input, 2+ renders a textarea.",
            "format": "int32",
            "nullable": true
          },
          "isRichText": {
            "type": "boolean",
            "description": "When true and Lines >= 2, the input renders as a rich text editor instead of a plain textarea."
          }
        },
        "additionalProperties": false,
        "description": "DTO for creating a custom token"
      },
      "CreateCustomerRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The customer or company name",
            "nullable": true
          },
          "email": {
            "type": "string",
            "description": "The customer's email address",
            "nullable": true
          },
          "contactNumber": {
            "type": "string",
            "description": "The customer's phone number",
            "nullable": true
          },
          "firstName": {
            "type": "string",
            "description": "The contact person's first name",
            "nullable": true
          },
          "lastName": {
            "type": "string",
            "description": "The contact person's last name",
            "nullable": true
          },
          "platformData": {
            "type": "object",
            "additionalProperties": {},
            "description": "Platform-specific data required for customer creation",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "DTO for creating a customer in an accounting platform"
      },
      "CreateDataFormCategoryRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The display name of the form category",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "DTO for creating a form category"
      },
      "CreateDataFormPreviewTokenResult": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CreateDataFormRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "introduction": {
            "type": "string",
            "nullable": true
          },
          "dataFormCategoryCode": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/DataFormStatus"
          },
          "defaultMessage": {
            "type": "string",
            "nullable": true
          },
          "sections": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DataFormSectionDto"
            },
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "DTO for creating or updating a form (whole-form save including sections and questions)"
      },
      "CreateDesignThemeRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Display name for the theme",
            "nullable": true
          },
          "isDefault": {
            "type": "boolean",
            "description": "Whether this should be the default theme for the tenant"
          },
          "heading1": {
            "$ref": "#/components/schemas/FontSettingsDto"
          },
          "heading2": {
            "$ref": "#/components/schemas/FontSettingsDto"
          },
          "heading3": {
            "$ref": "#/components/schemas/FontSettingsDto"
          },
          "body": {
            "$ref": "#/components/schemas/FontSettingsDto"
          },
          "tableHeader": {
            "$ref": "#/components/schemas/FontSettingsDto"
          },
          "tableCell": {
            "$ref": "#/components/schemas/FontSettingsDto"
          },
          "logoUrl": {
            "type": "string",
            "description": "URL to the company logo image",
            "nullable": true
          },
          "primaryColor": {
            "type": "string",
            "description": "Primary brand color in hex format (e.g., \"#000000\")",
            "nullable": true
          },
          "secondaryColor": {
            "type": "string",
            "description": "Secondary brand color in hex format",
            "nullable": true
          },
          "accentColor": {
            "type": "string",
            "description": "Accent color in hex format",
            "nullable": true
          },
          "backgroundColor": {
            "type": "string",
            "description": "Optional page background color in hex format (e.g., \"#FFFFFF\"). Null for transparent/default.",
            "nullable": true
          },
          "linkColor": {
            "type": "string",
            "description": "Optional link color in hex format (e.g., \"#1E88E5\"). Null for default.",
            "nullable": true
          },
          "linkHoverColor": {
            "type": "string",
            "description": "Optional link hover color in hex format (e.g., \"#0D47A1\"). Null for default.",
            "nullable": true
          },
          "primaryButton": {
            "$ref": "#/components/schemas/ButtonStyleDto"
          },
          "secondaryButton": {
            "$ref": "#/components/schemas/ButtonStyleDto"
          },
          "navBackgroundColor": {
            "type": "string",
            "description": "Navigation background color for the client portal (e.g., \"#1e293b\")",
            "nullable": true
          },
          "navTextColor": {
            "type": "string",
            "description": "Navigation text color for the client portal",
            "nullable": true
          },
          "navActiveBackgroundColor": {
            "type": "string",
            "description": "Active navigation item highlight color (supports rgba, e.g., \"rgba(255,255,255,0.15)\")",
            "nullable": true
          },
          "navActiveTextColor": {
            "type": "string",
            "description": "Active navigation item text color",
            "nullable": true
          },
          "cardBackgroundColor": {
            "type": "string",
            "description": "Card/panel background color in the content area",
            "nullable": true
          },
          "borderRadius": {
            "type": "integer",
            "description": "Global corner radius in pixels for cards, buttons, and inputs",
            "format": "int32",
            "nullable": true
          },
          "navFontSize": {
            "type": "number",
            "description": "Font size in points for the client portal navigation bar. Null falls back to body font size.",
            "format": "float",
            "nullable": true
          },
          "faviconUrl": {
            "type": "string",
            "description": "URL to a tenant-specific favicon for the client portal",
            "nullable": true
          },
          "pageMargins": {
            "$ref": "#/components/schemas/MarginsDto"
          },
          "customCSS": {
            "type": "string",
            "description": "Additional custom CSS rules to append to the generated theme CSS",
            "nullable": true
          },
          "headerTextContentBlockCode": {
            "type": "string",
            "description": "Code of the content block to use for document headers.\nPDF only: repeats at the top of each page. When set, PageMarginTop is ignored.",
            "nullable": true
          },
          "headerPageSelection": {
            "$ref": "#/components/schemas/PageSelection"
          },
          "footerContentBlockCode": {
            "type": "string",
            "description": "Code of the content block to use for document footers.\nPDF only: repeats at the bottom of each page.",
            "nullable": true
          },
          "footerPageSelection": {
            "$ref": "#/components/schemas/PageSelection"
          },
          "pageNumberDisplay": {
            "$ref": "#/components/schemas/PageSelection"
          }
        },
        "additionalProperties": false,
        "description": "Request to create a new design theme for document styling"
      },
      "CreateDocumentCategoryRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The display name of the document category",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "The sort order for displaying document categories",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "DTO for creating a document category"
      },
      "CreateDocumentRequestRequest": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "description": "Title describing what documents are needed",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Detailed description of what is needed",
            "nullable": true
          },
          "deadline": {
            "type": "string",
            "description": "Optional deadline for the client to respond by",
            "format": "date",
            "nullable": true
          },
          "notifyUserCode": {
            "type": "string",
            "description": "Code of the user to notify when a submission is made",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for creating a new document request"
      },
      "CreateDocumentTemplateRequest": {
        "required": [
          "bodyHtml",
          "name",
          "type"
        ],
        "type": "object",
        "properties": {
          "name": {
            "maxLength": 120,
            "minLength": 1,
            "type": "string",
            "description": "Display name for the template (e.g., \"Standard Engagement Letter\", \"Monthly Report\")"
          },
          "type": {
            "$ref": "#/components/schemas/TemplateType"
          },
          "bodyHtml": {
            "minLength": 1,
            "type": "string",
            "description": "Template body in HTML with Liquid syntax tokens.\nSupported tokens:\n- {{ client.name }} - Client's name\n- {{ client.companyNumber }} - Company registration number\n- {{ tenant.name }} - Your practice name\n- {{ date | date: \"%B %d, %Y\" }} - Current date (formatted)\n- {{ contentBlock \"block-code\" }} - Include a reusable content block\n- {% if client.isVatRegistered %} ... {% endif %} - Conditional content\n- {% for item in services %} ... {% endfor %} - Loop through collections\nCustom tokens can be passed via the Data parameter when rendering."
          },
          "description": {
            "maxLength": 500,
            "type": "string",
            "description": "Optional description explaining the template's purpose and usage",
            "nullable": true
          },
          "isActive": {
            "type": "boolean",
            "description": "Whether this template is available for use. Set to false to disable without deleting."
          },
          "outputNameTemplate": {
            "maxLength": 500,
            "type": "string",
            "description": "Optional template for naming rendered documents.\nSupports {{ token }} placeholders (e.g. \"Engagement Letter - {{ ClientName }} - {{ Month }} {{ Year }}\").\nWhen null or empty, documents use the template's Name.",
            "nullable": true
          },
          "defaultDesignThemeCode": {
            "type": "string",
            "description": "Code of the default design theme to apply when rendering this template.\nIf not specified, falls back to the tenant's default theme.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request to create a new document template that can generate documents using Liquid syntax.\nTemplates support tokens for dynamic data replacement and can include reusable content blocks."
      },
      "CreateEmailBroadcastRequest": {
        "type": "object",
        "properties": {
          "contentBlockCode": {
            "maxLength": 100,
            "type": "string",
            "description": "Content block code (category: Email) used as the email template.\nMutually exclusive with SubjectLine/BodyHtml — provide one or the other.",
            "nullable": true,
            "example": "client-newsletter"
          },
          "subjectLine": {
            "maxLength": 500,
            "type": "string",
            "description": "Inline email subject line with Liquid template syntax.\nMust be provided together with BodyHtml. Mutually exclusive with ContentBlockCode.",
            "nullable": true,
            "example": "An update for {{ Client.Name }}"
          },
          "bodyHtml": {
            "type": "string",
            "description": "Inline email body HTML with Liquid template syntax.\nMust be provided together with SubjectLine. Mutually exclusive with ContentBlockCode.",
            "nullable": true
          },
          "allContacts": {
            "type": "boolean",
            "description": "When true, every contact of each client with an email address receives the email\nas a To recipient, regardless of contact type. RecipientContactTypes is ignored.",
            "example": false
          },
          "recipientContactTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientContactType"
            },
            "description": "Client contact types for To recipients, resolved per client at send time.\nIgnored when AllContacts is true.",
            "nullable": true
          },
          "recipientUserTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowStepAssignmentType"
            },
            "description": "User types for To recipients (ClientManager, ClientPartner, ClientAssociate, ClientServiceManager),\nresolved per client at send time. TaskOwner and SpecificUser are not applicable for broadcasts.",
            "nullable": true
          },
          "additionalEmailAddresses": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Static email addresses to include as To recipients on every email.",
            "nullable": true
          },
          "ccContactTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientContactType"
            },
            "description": "Client contact types for CC recipients.",
            "nullable": true
          },
          "ccUserTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowStepAssignmentType"
            },
            "description": "User types for CC recipients.",
            "nullable": true
          },
          "ccEmailAddresses": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Static email addresses to include as CC recipients on every email.",
            "nullable": true
          },
          "bccContactTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientContactType"
            },
            "description": "Client contact types for BCC recipients.",
            "nullable": true
          },
          "bccUserTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowStepAssignmentType"
            },
            "description": "User types for BCC recipients.",
            "nullable": true
          },
          "bccEmailAddresses": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Static email addresses to include as BCC recipients on every email.",
            "nullable": true
          },
          "savedViewCode": {
            "maxLength": 100,
            "type": "string",
            "description": "The code of a saved client view whose filter selects which clients to include.\nThe view's criteria are resolved when recipients are resolved, so later changes to\nthe view are picked up until the broadcast is sent. Mutually exclusive with Filter.",
            "nullable": true,
            "example": "active-limited-companies"
          },
          "filter": {
            "$ref": "#/components/schemas/EmailBroadcastFilterDto"
          },
          "excludedClientCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Client codes to exclude from the filter results.",
            "nullable": true
          },
          "additionalClientCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Hand-picked client codes to add on top of the filter results.",
            "nullable": true
          },
          "onlyEmailableClients": {
            "type": "boolean",
            "description": "When true (default), clients whose email contact preference is not set are skipped.",
            "example": true
          },
          "addHeaderFooter": {
            "type": "boolean",
            "description": "When true (default), the tenant's email header and footer content blocks are\nwrapped around the body when the email is rendered.",
            "example": true
          },
          "configCode": {
            "maxLength": 100,
            "type": "string",
            "description": "The email configuration (mailbox) code to send from.\nOmit to use the tenant's default mailbox resolution.",
            "nullable": true,
            "example": "billing-mailbox"
          }
        },
        "additionalProperties": false,
        "description": "Request to create a draft email broadcast.\nProvide either a ContentBlockCode or inline SubjectLine + BodyHtml (mutually exclusive).\nRecipient selection combines an optional client filter with hand-picked additions and exclusions."
      },
      "CreateEmailConfigRequest": {
        "required": [
          "fromEmail",
          "providerType"
        ],
        "type": "object",
        "properties": {
          "providerType": {
            "$ref": "#/components/schemas/ProviderType"
          },
          "fromEmail": {
            "minLength": 1,
            "type": "string",
            "description": "The sender email address for this configuration"
          },
          "fromName": {
            "type": "string",
            "description": "The sender display name (optional)",
            "nullable": true
          },
          "isDefault": {
            "type": "boolean",
            "description": "Whether to set this as the tenant's default email configuration.\nIf true, IsSendShared must also be true."
          },
          "isSendShared": {
            "type": "boolean",
            "description": "Whether all users in the tenant can send emails from this configuration"
          },
          "isReadShared": {
            "type": "boolean",
            "description": "Whether all users in the tenant can read the emails received in this mailbox"
          },
          "smtpSettings": {
            "$ref": "#/components/schemas/SmtpSettingsRequest"
          },
          "oAuthSettings": {
            "$ref": "#/components/schemas/OAuthSettingsRequest"
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for creating a new email configuration"
      },
      "CreateEngagementRequest": {
        "required": [
          "clientCode",
          "date",
          "type"
        ],
        "type": "object",
        "properties": {
          "clientCode": {
            "minLength": 1,
            "type": "string",
            "description": "Code of the client this engagement belongs to"
          },
          "date": {
            "type": "string",
            "description": "Date of the engagement",
            "format": "date"
          },
          "type": {
            "$ref": "#/components/schemas/EngagementType"
          },
          "recipientFirstName": {
            "type": "string",
            "description": "First name of the recipient for this engagement",
            "nullable": true
          },
          "recipientLastName": {
            "type": "string",
            "description": "Last name of the recipient for this engagement",
            "nullable": true
          },
          "recipientEmail": {
            "type": "string",
            "description": "Email address of the recipient for this engagement",
            "nullable": true
          },
          "requestDdMandate": {
            "type": "boolean",
            "description": "Per-proposal override for the \"set up Direct Debit\" acceptance step.\nNull leaves the practice default (from proposal settings) in effect for this proposal.",
            "nullable": true
          },
          "requestAmlOnboarding": {
            "type": "boolean",
            "description": "Per-proposal override for the identity-verification (AML) acceptance step.\nNull leaves the practice default (from proposal settings) in effect for this proposal.",
            "nullable": true
          },
          "proposalTemplateCode": {
            "type": "string",
            "description": "Code of the template to use for the proposal document",
            "nullable": true
          },
          "lofETemplateCode": {
            "type": "string",
            "description": "Code of the template to use for the letter of engagement (LofE) document",
            "nullable": true
          },
          "clientBillableServiceCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of ClientBillableService codes to include in this engagement.\n            \nIMPORTANT: The system will create a historical snapshot of each ClientBillableService at its current state.\nThis snapshot is stored as JSON and preserves the service details even if the original\nClientBillableService is later modified or deleted.\n            \nThe snapshot includes: name, description, price, billing frequency, start/end dates, and the\nClientBillableServiceCode for reference.\n            \nExample: [\"CBS001\", \"CBS002\", \"CBS003\"]",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for creating a new engagement"
      },
      "CreateOnboardingReportRequest": {
        "required": [
          "levelId"
        ],
        "type": "object",
        "properties": {
          "levelId": {
            "minLength": 1,
            "type": "string",
            "description": "The onboarding level ID to use."
          },
          "sendEmail": {
            "type": "boolean",
            "description": "Whether to send the onboarding email to the contact."
          },
          "mailTemplateId": {
            "type": "string",
            "description": "The mail template ID to use when sending the email. Required when SendEmail is true.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request to create an onboarding report for a contact in the AML platform."
      },
      "CreateOnboardingTaskTemplateRequest": {
        "required": [
          "billableServiceCode"
        ],
        "type": "object",
        "properties": {
          "billableServiceCode": {
            "minLength": 1,
            "type": "string",
            "description": "Code of the billable service this template belongs to"
          },
          "name": {
            "type": "string",
            "description": "The name of the onboarding task",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "The description of the onboarding task",
            "nullable": true
          },
          "timeEstimateMinutes": {
            "type": "integer",
            "description": "The estimated time to complete the task, in whole minutes.",
            "format": "int32",
            "nullable": true
          },
          "dueDateOffsetDays": {
            "type": "integer",
            "description": "Days after service start date for the task due date",
            "format": "int32"
          },
          "assignmentType": {
            "$ref": "#/components/schemas/AssignmentType"
          },
          "assignedUserCode": {
            "type": "string",
            "description": "Code of the user to assign tasks to (only used if AssignmentType is SpecificUser)",
            "nullable": true
          },
          "assignedTeamCode": {
            "type": "string",
            "description": "Code of the team to assign tasks to (optional, independent of AssignmentType)",
            "nullable": true
          },
          "workflowCode": {
            "type": "string",
            "description": "Code of the workflow template to apply to generated tasks",
            "nullable": true
          },
          "categoryCode": {
            "type": "string",
            "description": "Code of the category to apply to generated tasks",
            "nullable": true
          },
          "checklist": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChecklistItemDto"
            },
            "description": "Checklist items for this onboarding task template",
            "nullable": true
          },
          "active": {
            "type": "boolean",
            "description": "Whether this template is active"
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for creating a new onboarding task template"
      },
      "CreatePipelineOnboardingTaskTemplateRequest": {
        "required": [
          "pipelineCode"
        ],
        "type": "object",
        "properties": {
          "pipelineCode": {
            "minLength": 1,
            "type": "string",
            "description": "Code of the pipeline this template belongs to"
          },
          "name": {
            "type": "string",
            "description": "The name of the intake task",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "The description of the intake task",
            "nullable": true
          },
          "timeEstimateMinutes": {
            "type": "integer",
            "description": "The estimated time to complete the task, in whole minutes.",
            "format": "int32",
            "nullable": true
          },
          "dueDateOffsetDays": {
            "type": "integer",
            "description": "Days after the card's start date for the task due date",
            "format": "int32"
          },
          "assignmentType": {
            "$ref": "#/components/schemas/AssignmentType"
          },
          "assignedUserCode": {
            "type": "string",
            "description": "Code of the user to assign tasks to (only used if AssignmentType is SpecificUser)",
            "nullable": true
          },
          "assignedTeamCode": {
            "type": "string",
            "description": "Code of the team to assign tasks to (optional, independent of AssignmentType)",
            "nullable": true
          },
          "workflowCode": {
            "type": "string",
            "description": "Code of the workflow template to apply to generated tasks",
            "nullable": true
          },
          "categoryCode": {
            "type": "string",
            "description": "Code of the category to apply to generated tasks",
            "nullable": true
          },
          "checklist": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChecklistItemDto"
            },
            "description": "Checklist items for this intake task template",
            "nullable": true
          },
          "active": {
            "type": "boolean",
            "description": "Whether this template is active"
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for creating a new pipeline intake task template"
      },
      "CreatePipelineRequest": {
        "required": [
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "minLength": 1,
            "type": "string",
            "description": "The name of the pipeline"
          },
          "description": {
            "type": "string",
            "description": "The description of the pipeline",
            "nullable": true
          },
          "isArchived": {
            "type": "boolean",
            "description": "Indicates whether this pipeline is archived (inactive)"
          },
          "defaultManagedByUserCode": {
            "type": "string",
            "description": "The code of the user who is the default manager for this pipeline",
            "nullable": true
          },
          "showKanbanBoard": {
            "type": "boolean",
            "description": "Whether this pipeline should appear on the Boards kanban view"
          },
          "stages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PipelineStageDto"
            },
            "description": "User-defined stages for this pipeline",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for creating a new sales pipeline"
      },
      "CreateProfessionalClearanceRequestItemRequest": {
        "type": "object",
        "properties": {
          "request": {
            "type": "string",
            "description": "The request text",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "The sort order for displaying the requests",
            "format": "int32"
          },
          "global": {
            "type": "boolean",
            "description": "If true, this item will be included for all clients regardless of the services they have"
          }
        },
        "additionalProperties": false,
        "description": "DTO for creating a professional clearance request item"
      },
      "CreateRecurringTaskItemRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The name of the recurring task",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "The description of the recurring task",
            "nullable": true
          },
          "timeEstimateMinutes": {
            "type": "integer",
            "description": "The estimated time to complete the task, in whole minutes.",
            "format": "int32",
            "nullable": true
          },
          "assignedUserCode": {
            "type": "string",
            "description": "Code of the user to assign tasks to (only used if AssignmentType is SpecificUser)",
            "nullable": true
          },
          "assignedTeamCode": {
            "type": "string",
            "description": "Code of the team to assign tasks to (optional, independent of AssignmentType)",
            "nullable": true
          },
          "billableServiceCode": {
            "type": "string",
            "description": "Code of the billable service (only used if AssignmentType is ClientServiceManager)",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "Sort order for displaying recurring tasks",
            "format": "int32",
            "nullable": true
          },
          "active": {
            "type": "boolean",
            "description": "Whether this recurring task is active and will generate new tasks"
          },
          "taskStartConfig": {
            "$ref": "#/components/schemas/TaskStartConfigDto"
          },
          "dueDateConfig": {
            "$ref": "#/components/schemas/DueDateConfigDto"
          },
          "statutoryDateConfig": {
            "$ref": "#/components/schemas/StatutoryDateConfigDto"
          },
          "recurrence": {
            "$ref": "#/components/schemas/RecurrenceConfigDto"
          },
          "taskDateBasis": {
            "$ref": "#/components/schemas/TaskDateBasis"
          },
          "startHolidayAdjustment": {
            "$ref": "#/components/schemas/HolidayAdjustment"
          },
          "dueHolidayAdjustment": {
            "$ref": "#/components/schemas/HolidayAdjustment"
          },
          "assignmentType": {
            "$ref": "#/components/schemas/AssignmentType"
          },
          "workflowCode": {
            "type": "string",
            "description": "Code of the workflow template to apply to generated tasks",
            "nullable": true
          },
          "categoryCode": {
            "type": "string",
            "description": "Code of the category to apply to generated tasks (optional)",
            "nullable": true
          },
          "clientAssociationType": {
            "$ref": "#/components/schemas/ClientAssociationType"
          },
          "vatReportingPeriod": {
            "$ref": "#/components/schemas/VatReportingPeriod"
          },
          "checklist": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChecklistItemDto"
            },
            "description": "Checklist items for this recurring task template",
            "nullable": true
          },
          "taskNameTemplate": {
            "maxLength": 500,
            "type": "string",
            "description": "Optional template for naming tasks created from this recurring task.\nSupports {{ token }} placeholders (e.g. \"VAT Return - {{ ClientName }} - {{ Quarter }} {{ Year }}\").\nWhen null or empty, tasks use the recurring task's Name.\nAvailable tokens can be retrieved from the GET /metadata/task-name-tokens endpoint.\nUnrecognised tokens are left as-is in generated task names.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for creating a new recurring task template"
      },
      "CreateRevenueRangeRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The display name of the revenue range (e.g., \"£30k - £70k\")",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "The sort order for displaying revenue ranges",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "DTO for creating a revenue range"
      },
      "CreateRiskAssessmentRequest": {
        "type": "object",
        "properties": {
          "templateId": {
            "type": "string",
            "description": "Optional questionnaire template ID. If provided, a questionnaire based on this template is attached to the risk assessment.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request to create a new risk assessment in the AML platform."
      },
      "CreateSavedClientFilterRequest": {
        "required": [
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "maxLength": 200,
            "minLength": 1,
            "type": "string",
            "description": "User-friendly name for this saved filter (e.g., \"Active Limited Companies\", \"My Managed Clients\")"
          },
          "description": {
            "maxLength": 1000,
            "type": "string",
            "description": "Optional description providing more details about this filter's purpose",
            "nullable": true
          },
          "includeInMenu": {
            "type": "boolean",
            "description": "Whether this filter should be included in the current user's menu/quick access list.\nThis is a per-user preference — it does not affect other users of a shared filter."
          },
          "isShared": {
            "type": "boolean",
            "description": "Whether this filter is shared with all users in the tenant. Shared filters are\nvisible (read-only) to everyone; only the owner can modify or delete them."
          },
          "managerCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by manager code(s)",
            "nullable": true
          },
          "partnerCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by partner code(s)",
            "nullable": true
          },
          "associateCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by associate code(s)",
            "nullable": true
          },
          "statuses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientStatus"
            },
            "description": "Filter by client status(es)",
            "nullable": true
          },
          "types": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientType"
            },
            "description": "Filter by client type(s)",
            "nullable": true
          },
          "serviceCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by billable service code(s)",
            "nullable": true
          },
          "packageCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by service package code(s)",
            "nullable": true
          },
          "teamCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by team code(s)",
            "nullable": true
          },
          "serviceStageCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by service stage composite codes (format: \"serviceCode:stageCode\")",
            "nullable": true
          },
          "defaultSortField": {
            "$ref": "#/components/schemas/ClientSortField"
          },
          "defaultSortDesc": {
            "type": "boolean",
            "description": "Sort in descending order (true) or ascending order (false)",
            "nullable": true
          },
          "iconName": {
            "maxLength": 100,
            "type": "string",
            "description": "Optional Lucide icon name for visual identification (e.g., \"Calendar\", \"Users\", \"Star\")",
            "nullable": true
          },
          "color": {
            "maxLength": 7,
            "type": "string",
            "description": "Optional hex color for visual identification (e.g., \"#FF5733\")",
            "nullable": true
          },
          "columnConfigJson": {
            "type": "string",
            "description": "Optional JSON column configuration for the saved view.\nWhen set, overrides the user's default client column preferences.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request model for creating a new saved client filter"
      },
      "CreateSavedTaskFilterRequest": {
        "required": [
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "maxLength": 200,
            "minLength": 1,
            "type": "string",
            "description": "User-friendly name for this saved filter (e.g., \"My Overdue Tasks\", \"Client ABC Tasks\")"
          },
          "description": {
            "maxLength": 1000,
            "type": "string",
            "description": "Optional description providing more details about this filter's purpose",
            "nullable": true
          },
          "includeInMenu": {
            "type": "boolean",
            "description": "Whether this filter should be included in the current user's menu/quick access list.\nThis is a per-user preference — it does not affect other users of a shared filter."
          },
          "isShared": {
            "type": "boolean",
            "description": "Whether this filter is shared with all users in the tenant. Shared filters are\nvisible (read-only) to everyone; only the owner can modify or delete them."
          },
          "dateRange": {
            "$ref": "#/components/schemas/PresetDateRange"
          },
          "startDate": {
            "type": "string",
            "description": "Custom start date (only used when DateRange = CustomDateRange)",
            "format": "date",
            "nullable": true
          },
          "endDate": {
            "type": "string",
            "description": "Custom end date (only used when DateRange = CustomDateRange)",
            "format": "date",
            "nullable": true
          },
          "dateBasis": {
            "$ref": "#/components/schemas/TaskDateBasis"
          },
          "clientCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by client code(s)",
            "nullable": true
          },
          "userCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by user code(s)",
            "nullable": true
          },
          "recurringTaskCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by recurring task code(s)",
            "nullable": true
          },
          "categoryCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by category code(s)",
            "nullable": true
          },
          "teamCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by team code(s)",
            "nullable": true
          },
          "statuses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TaskItemStatus"
            },
            "description": "Filter by task status(es)",
            "nullable": true
          },
          "isOverdue": {
            "type": "boolean",
            "description": "Filter to only overdue tasks",
            "nullable": true
          },
          "isUnassigned": {
            "type": "boolean",
            "description": "Include tasks with no assigned user. Can be combined with UserCodes to show\ntasks that are either unassigned OR assigned to specific users.",
            "nullable": true
          },
          "includeProjected": {
            "type": "boolean",
            "description": "Include projected (virtual) tasks in the results"
          },
          "includeWorkflowSteps": {
            "type": "boolean",
            "description": "Include workflow steps in the results (Agenda mode)"
          },
          "defaultSortField": {
            "$ref": "#/components/schemas/TaskItemSortField"
          },
          "defaultSortDesc": {
            "type": "boolean",
            "description": "Sort in descending order (true) or ascending order (false)",
            "nullable": true
          },
          "iconName": {
            "maxLength": 100,
            "type": "string",
            "description": "Optional Lucide icon name for visual identification (e.g., \"Calendar\", \"Users\", \"Star\")",
            "nullable": true
          },
          "color": {
            "maxLength": 7,
            "type": "string",
            "description": "Optional hex color for visual identification (e.g., \"#FF5733\")",
            "nullable": true
          },
          "columnConfigJson": {
            "type": "string",
            "description": "Optional JSON column configuration for the saved view.\nWhen set, overrides the user's default task column preferences.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request model for creating a new saved task filter"
      },
      "CreateServicePackageItemRequest": {
        "required": [
          "billableServiceCode"
        ],
        "type": "object",
        "properties": {
          "billableServiceCode": {
            "minLength": 1,
            "type": "string",
            "description": "The code of the billable service to include"
          },
          "billingFrequency": {
            "$ref": "#/components/schemas/BillingFrequency"
          },
          "overridePricing": {
            "type": "boolean",
            "description": "Whether to override the standard pricing from the billable service"
          },
          "price": {
            "type": "number",
            "description": "The custom price to use when OverridePricing is true",
            "format": "double",
            "nullable": true
          },
          "pricingAnswers": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Pre-answered pricing factors (key = factor description, value = selected option name)",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for a service to include in a service package"
      },
      "CreateServicePackageRequest": {
        "required": [
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "minLength": 1,
            "type": "string",
            "description": "The name of the service package"
          },
          "description": {
            "type": "string",
            "description": "Description of what this package includes",
            "nullable": true
          },
          "isArchived": {
            "type": "boolean",
            "description": "Whether this package is archived (inactive)"
          },
          "usePackagePricing": {
            "type": "boolean",
            "description": "Whether this package uses a single package-level price instead of summing individual item prices"
          },
          "packagePrice": {
            "type": "number",
            "description": "The flat price for the entire package. Required when UsePackagePricing is true.",
            "format": "double",
            "nullable": true
          },
          "packageBillingFrequency": {
            "$ref": "#/components/schemas/BillingFrequency"
          },
          "packageSetupFee": {
            "minimum": 0,
            "type": "number",
            "description": "Optional one-off setup fee for the package, billed once when the package is first invoiced.\nOnly used when UsePackagePricing is true. Null means no setup fee.",
            "format": "double",
            "nullable": true
          },
          "proposalContentCode": {
            "type": "string",
            "description": "The code of the proposal content block. Only used when UsePackagePricing is true.\nWhen set, overrides the individual content blocks defined on each service in the package.\nWhen null, proposals fall back to each service's own proposal content block.",
            "nullable": true
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CreateServicePackageItemRequest"
            },
            "description": "The services to include in this package",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for creating a new service package"
      },
      "CreateTaskCategoryRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The display name of the task category",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "The sort order for displaying task categories",
            "format": "int32"
          },
          "color": {
            "type": "string",
            "description": "The color associated with this task category",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "DTO for creating a task category"
      },
      "CreateTaskItemNoteRequest": {
        "required": [
          "date",
          "noteFromUserCode",
          "text"
        ],
        "type": "object",
        "properties": {
          "text": {
            "minLength": 1,
            "type": "string",
            "description": "The text content of the note"
          },
          "date": {
            "type": "string",
            "description": "The date/time the note was created",
            "format": "date-time"
          },
          "noteFromUserCode": {
            "minLength": 1,
            "type": "string",
            "description": "The code of the user who authored this note"
          },
          "pinnedLevel": {
            "type": "integer",
            "description": "The pinned level for ordering pinned notes",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for creating a new task item note"
      },
      "CreateTaskItemRequest": {
        "required": [
          "dueDate",
          "name",
          "startDate",
          "status"
        ],
        "type": "object",
        "properties": {
          "name": {
            "minLength": 1,
            "type": "string",
            "description": "The name of the task"
          },
          "description": {
            "type": "string",
            "description": "The description of the task",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/TaskItemStatus"
          },
          "timeEstimateMinutes": {
            "type": "integer",
            "description": "The estimated time to complete the task, in whole minutes.",
            "format": "int32",
            "nullable": true
          },
          "startDate": {
            "type": "string",
            "description": "When the task starts",
            "format": "date"
          },
          "dueDate": {
            "type": "string",
            "description": "When the task is due",
            "format": "date"
          },
          "statutoryDueDate": {
            "type": "string",
            "description": "The statutory due date for compliance tasks (if applicable)",
            "format": "date",
            "nullable": true
          },
          "clientCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The codes of the clients this task is associated with (optional)",
            "nullable": true
          },
          "primaryClientCode": {
            "type": "string",
            "description": "The code of the primary client for this task (optional)",
            "nullable": true
          },
          "assignedUserCode": {
            "type": "string",
            "description": "The code of the user to assign the task to (optional)",
            "nullable": true
          },
          "assignedTeamCode": {
            "type": "string",
            "description": "The code of the team to assign the task to (optional)",
            "nullable": true
          },
          "clientBillableServiceCode": {
            "type": "string",
            "description": "The code of the client billable service this task relates to (optional)",
            "nullable": true
          },
          "categoryCode": {
            "type": "string",
            "description": "The code of the category for this task (optional)",
            "nullable": true
          },
          "checklist": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChecklistItemDto"
            },
            "description": "Checklist items for this task",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request model for creating a new task"
      },
      "CreateTeamRequest": {
        "required": [
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "maxLength": 200,
            "minLength": 1,
            "type": "string",
            "description": "The display name of the team"
          },
          "description": {
            "maxLength": 500,
            "type": "string",
            "description": "Optional description of the team's purpose",
            "nullable": true
          },
          "iconName": {
            "maxLength": 100,
            "type": "string",
            "description": "Optional Lucide icon name for visual identification",
            "nullable": true
          },
          "color": {
            "maxLength": 7,
            "type": "string",
            "description": "Optional hex color for visual identification",
            "nullable": true
          },
          "canBeAssignedToTasks": {
            "type": "boolean",
            "description": "Whether this team can be assigned to tasks"
          },
          "canBeAssignedToClients": {
            "type": "boolean",
            "description": "Whether this team can be assigned to clients"
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for creating a team"
      },
      "CreateTenantHolidayRequest": {
        "type": "object",
        "properties": {
          "date": {
            "type": "string",
            "description": "The date of the holiday (format: yyyy-MM-dd)",
            "format": "date"
          },
          "name": {
            "type": "string",
            "description": "Name of the holiday (e.g., \"Company Anniversary\", \"Office Closure\")",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request to create a tenant-specific holiday"
      },
      "CreateTenantUserRequest": {
        "required": [
          "email"
        ],
        "type": "object",
        "properties": {
          "roleType": {
            "$ref": "#/components/schemas/RoleType"
          },
          "roleId": {
            "type": "integer",
            "description": "The ID of the custom role (only used if RoleType is Custom)",
            "format": "int32",
            "nullable": true
          },
          "systemRoleType": {
            "$ref": "#/components/schemas/SystemRole"
          },
          "isClientManager": {
            "type": "boolean",
            "description": "Whether the user is a client manager within the tenant"
          },
          "isPartner": {
            "type": "boolean",
            "description": "Whether the user is a partner within the tenant"
          },
          "isAssociate": {
            "type": "boolean",
            "description": "Whether the user is an associate within the tenant"
          },
          "isRestrictedToTeamClients": {
            "type": "boolean",
            "description": "Whether the user can only see clients belonging to their teams"
          },
          "isRestrictedToAssignedClients": {
            "type": "boolean",
            "description": "Whether the user can only see clients where they are Manager, Partner, or Associate"
          },
          "hourlyRate": {
            "maximum": 100000,
            "minimum": 0,
            "type": "number",
            "description": "Charge-out rate per hour for time tracking.\nFalls back to the practice default rate when null.",
            "format": "double",
            "nullable": true
          },
          "email": {
            "minLength": 1,
            "type": "string",
            "format": "email"
          },
          "firstName": {
            "type": "string",
            "description": "The user's first name (required for creating new users)",
            "nullable": true
          },
          "lastName": {
            "type": "string",
            "description": "The user's last name (required for creating new users)",
            "nullable": true
          },
          "teamCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Optional list of team codes to assign the user to on creation",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "DTO for creating a user within a tenant. Inherits update fields and adds email/name for creation."
      },
      "CreateThirdPartyConnectionRequest": {
        "required": [
          "platform"
        ],
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Display name for the connection",
            "nullable": true
          },
          "redirectUrl": {
            "type": "string",
            "description": "URL to redirect the user to after OAuth flow completes. \nIf you use [code] in the url then we'll replace it with the Code of this ThirdPartyConnection.\nThis solves the problem of not knowing the code at creation time.",
            "nullable": true
          },
          "platform": {
            "minLength": 1,
            "type": "string",
            "description": "The platform identifier (e.g., \"Xero\", \"FreeAgent\", \"Xama\")"
          },
          "apiKey": {
            "type": "string",
            "description": "API key for ApiKey-authenticated platforms (e.g., Socket personal access token)",
            "nullable": true
          },
          "oAuthClientId": {
            "type": "string",
            "description": "OAuth client ID for OAuthClientCredentials flow (e.g., Xama OAuth ID)",
            "nullable": true
          },
          "oAuthClientSecret": {
            "type": "string",
            "description": "OAuth client secret for OAuthClientCredentials flow (e.g., Xama OAuth Secret)",
            "nullable": true
          },
          "organizationId": {
            "type": "string",
            "description": "External organization/client ID for OAuthClientCredentials flow (e.g., Xama Client ID)",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request for creating a new ThirdPartyConnection"
      },
      "CreateTimeEntryRequest": {
        "required": [
          "entryDate"
        ],
        "type": "object",
        "properties": {
          "userCode": {
            "type": "string",
            "description": "The code of the team member who did the work. Defaults to the calling user when omitted.",
            "nullable": true
          },
          "entryDate": {
            "type": "string",
            "description": "The day the work was done (format: yyyy-MM-dd)",
            "format": "date"
          },
          "durationMinutes": {
            "maximum": 1440,
            "minimum": 1,
            "type": "integer",
            "description": "How long the work took, in minutes",
            "format": "int32"
          },
          "startTime": {
            "type": "string",
            "description": "When the work started (UTC) — optional, set by timer-logged entries",
            "format": "date-time",
            "nullable": true
          },
          "endTime": {
            "type": "string",
            "description": "When the work ended (UTC) — optional, set by timer-logged entries",
            "format": "date-time",
            "nullable": true
          },
          "description": {
            "maxLength": 1000,
            "type": "string",
            "description": "What the time was spent on",
            "nullable": true
          },
          "clientCode": {
            "type": "string",
            "description": "The code of the client the time relates to (optional unless the practice requires linking)",
            "nullable": true
          },
          "taskItemCode": {
            "type": "string",
            "description": "The code of the task the time relates to (optional unless the practice requires linking)",
            "nullable": true
          },
          "workflowGroupNumber": {
            "type": "integer",
            "description": "The group number of the workflow step the time relates to (optional; requires\nTaskItemCode and WorkflowStepNumber)",
            "format": "int32",
            "nullable": true
          },
          "workflowStepNumber": {
            "type": "integer",
            "description": "The step number of the workflow step the time relates to (optional; requires\nTaskItemCode and WorkflowGroupNumber)",
            "format": "int32",
            "nullable": true
          },
          "blocks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TimerBlockDto"
            },
            "description": "The work blocks the entry was logged from, for timer-logged entries. When\nprovided, StartTime, EndTime and DurationMinutes are derived from the blocks\n(span start, span end, summed working time) and any supplied values are ignored.\nEach block needs either a start and end time or a duration in minutes.",
            "nullable": true
          },
          "isBillable": {
            "type": "boolean",
            "description": "Whether this time can be billed to the client"
          },
          "hourlyRate": {
            "maximum": 100000,
            "minimum": 0,
            "type": "number",
            "description": "Charge-out rate per hour. When omitted on a billable entry, defaults from the\nteam member's rate, then the practice default rate.",
            "format": "double",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request to create a time entry"
      },
      "CreateWorkflowRequest": {
        "required": [
          "groups",
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "maxLength": 100,
            "minLength": 0,
            "type": "string",
            "description": "The name of the workflow"
          },
          "description": {
            "type": "string",
            "description": "Optional description explaining the workflow's purpose",
            "nullable": true
          },
          "groups": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowGroupDto"
            },
            "description": "The workflow groups containing steps"
          },
          "deadlineRelativeTo": {
            "$ref": "#/components/schemas/DeadlineReferenceType"
          }
        },
        "additionalProperties": false,
        "description": "Request to create a new workflow"
      },
      "CsvColumnMappingDto": {
        "type": "object",
        "properties": {
          "csvHeader": {
            "type": "string",
            "description": "The CSV column header name exactly as it appears in the file.\nMust match the header row in the CSV (case-sensitive).",
            "nullable": true,
            "example": "Company Number"
          },
          "targetField": {
            "$ref": "#/components/schemas/ClientCsvTargetField"
          },
          "customFieldCode": {
            "type": "string",
            "description": "The code of the client custom field this column maps to. Null when SodiumHQ.DTOs.CsvImport.CsvColumnMappingDto.TargetField is set.",
            "nullable": true,
            "example": "annual-turnover"
          }
        },
        "additionalProperties": false,
        "description": "Represents a single column mapping from a CSV header to a client field.\nUsed in column mapping configurations to specify how CSV data maps to client records."
      },
      "CsvExportFilterDto": {
        "type": "object",
        "properties": {
          "managerCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter clients by their assigned manager's code(s).",
            "nullable": true
          },
          "partnerCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter clients by their assigned partner's code(s).",
            "nullable": true
          },
          "associateCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter clients by their assigned associate's code(s).",
            "nullable": true
          },
          "statuses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientStatus"
            },
            "description": "Filter clients by status(es).\nValues: Active, Inactive, Prospect, LostProspect",
            "nullable": true
          },
          "types": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientType"
            },
            "description": "Filter clients by their organization type(s).\nValues: Individual, Partnership, LLP, PrivateLimitedCompany, PublicLimitedCompany, Charity, Club, Trust, PublicSectorBody, OverseasCompany",
            "nullable": true
          },
          "serviceCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter clients by billable service code(s) they have assigned.",
            "nullable": true
          },
          "search": {
            "type": "string",
            "description": "Search across client code, name and internal reference.\nMinimum 3 characters.",
            "nullable": true,
            "example": "acme"
          }
        },
        "additionalProperties": false,
        "description": "Filter criteria for selecting which clients to export.\nMatches the same filters available on the client list endpoint."
      },
      "CsvExportJobDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique code identifying this export job.\nUse this code to poll for status via GET /clients/export/csv/{code}.",
            "nullable": true,
            "example": "exp-abc123"
          },
          "status": {
            "$ref": "#/components/schemas/ImportJobStatus"
          },
          "totalItems": {
            "type": "integer",
            "description": "Total number of clients to export.\nSet when the export job starts processing.",
            "format": "int32",
            "example": 150
          },
          "processedItems": {
            "type": "integer",
            "description": "Number of clients that have been written to the CSV so far.\nCompare with TotalItems to calculate progress percentage.",
            "format": "int32",
            "example": 75
          },
          "downloadUrl": {
            "type": "string",
            "description": "URL to download the generated CSV file.\nOnly available when Status is Completed.\nThis is a time-limited SAS URL that expires after the export job's expiry date.",
            "nullable": true,
            "example": "https://storage.blob.core.windows.net/csv-exports/tenant-123/exp-abc123.csv?sv=2021-06-08&se=2024-01-16T10:30:00Z..."
          },
          "startedDate": {
            "type": "string",
            "description": "When the job started processing (UTC).\nNull if the job hasn't started yet (status is Queued).",
            "format": "date-time",
            "nullable": true,
            "example": "2024-01-15T10:30:00Z"
          },
          "completedDate": {
            "type": "string",
            "description": "When the job completed processing (UTC).\nNull if the job hasn't completed yet (status is Queued or InProgress).\nSet for both successful completion and failure.",
            "format": "date-time",
            "nullable": true,
            "example": "2024-01-15T10:31:45Z"
          },
          "createdDate": {
            "type": "string",
            "description": "When the export job was created (UTC).",
            "format": "date-time",
            "example": "2024-01-15T10:30:00Z"
          }
        },
        "additionalProperties": false,
        "description": "Represents the current status and progress of a CSV export job.\nReturned when starting an export or polling for status.\nUse this to track progress and obtain the download URL when complete."
      },
      "CsvExportRequestDto": {
        "type": "object",
        "properties": {
          "mappingCode": {
            "type": "string",
            "description": "Code of an existing saved mapping to use for column headers.\nUse GET /clients/import/csv/mappings to list available mappings.\nMutually exclusive with ColumnMappings - provide one or the other.\nIf neither is provided, all fields are exported with enum names as headers.",
            "nullable": true,
            "example": "limited-company-clients"
          },
          "columnMappings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CsvColumnMappingDto"
            },
            "description": "Inline column mappings for the export.\nEach mapping specifies which client field maps to which CSV header.\nMutually exclusive with MappingCode - provide one or the other.\nIf neither is provided, all fields are exported with enum names as headers.",
            "nullable": true
          },
          "includeHeaders": {
            "type": "boolean",
            "description": "Whether to include a header row in the CSV output.\nDefault: true",
            "example": true
          },
          "filter": {
            "$ref": "#/components/schemas/CsvExportFilterDto"
          }
        },
        "additionalProperties": false,
        "description": "Request to start a CSV export of clients.\nSpecify column mappings and optional filter criteria to control the export output."
      },
      "CsvImportJobDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique code identifying this import job.\nUse this code to poll for status via GET /{code}.",
            "nullable": true,
            "example": "csv-abc123"
          },
          "status": {
            "$ref": "#/components/schemas/ImportJobStatus"
          },
          "fileName": {
            "type": "string",
            "description": "Original filename of the uploaded CSV file.",
            "nullable": true,
            "example": "clients-export-2024.csv"
          },
          "totalItems": {
            "type": "integer",
            "description": "Total number of data rows to import (excluding header row).\nMay be null if the job hasn't started processing yet.",
            "format": "int32",
            "nullable": true,
            "example": 150
          },
          "processedItems": {
            "type": "integer",
            "description": "Number of rows that have been processed so far.\nCompare with totalItems to calculate progress percentage.",
            "format": "int32",
            "example": 75
          },
          "createdCount": {
            "type": "integer",
            "description": "Number of new client records created during import.\nOnly incremented when importMode is CreateOnly or CreateAndUpdate.",
            "format": "int32",
            "example": 50
          },
          "updatedCount": {
            "type": "integer",
            "description": "Number of existing client records updated during import.\nOnly incremented when a match is found and importMode is UpdateOnly or CreateAndUpdate.",
            "format": "int32",
            "example": 20
          },
          "skippedCount": {
            "type": "integer",
            "description": "Number of rows skipped during import.\nReasons for skipping:\n- importMode is CreateOnly and a matching client already exists\n- importMode is UpdateOnly and no matching client was found\n- Row is missing required fields (e.g., Name)",
            "format": "int32",
            "example": 3
          },
          "errorCount": {
            "type": "integer",
            "description": "Number of rows that failed with errors during import.\nErrors may include validation failures or database errors.\nThe import continues processing remaining rows after an error.",
            "format": "int32",
            "example": 2
          },
          "warningCount": {
            "type": "integer",
            "description": "Number of rows that imported but had one or more custom field values skipped (partial imports).\nThese rows are included in the non-imported report, distinguished by their reason.",
            "format": "int32",
            "example": 3
          },
          "startedDate": {
            "type": "string",
            "description": "When the job started processing (UTC).\nNull if the job hasn't started yet (status is Queued).",
            "format": "date-time",
            "nullable": true,
            "example": "2024-01-15T10:30:00Z"
          },
          "completedDate": {
            "type": "string",
            "description": "When the job completed processing (UTC).\nNull if the job hasn't completed yet (status is Queued or Processing).\nSet for both successful completion and failure.",
            "format": "date-time",
            "nullable": true,
            "example": "2024-01-15T10:31:45Z"
          },
          "createdDate": {
            "type": "string",
            "description": "When the import job was created (UTC).\nThis is when the CSV file was uploaded.",
            "format": "date-time",
            "example": "2024-01-15T10:30:00Z"
          },
          "notImportedDownloadUrl": {
            "type": "string",
            "description": "URL to download a CSV containing rows that were not imported (errors and skips).\nOnly available when status is Completed and there were errors or skipped rows.\nThe CSV has the same columns as the source file plus Row and Reason columns,\nso it can be re-imported directly after fixing issues.\nThis is a time-limited SAS URL that expires after 60 minutes.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Represents the current status and progress of a CSV import job.\nReturned when starting an import or polling for status.\nUse this to track progress and final results of the import operation."
      },
      "CsvImportMatchField": {
        "enum": [
          "Code",
          "Name",
          "CompanyNumber",
          "InternalReference",
          "NiNumber"
        ],
        "type": "string"
      },
      "CsvImportMode": {
        "enum": [
          "CreateOnly",
          "UpdateOnly",
          "CreateAndUpdate"
        ],
        "type": "string"
      },
      "CsvMappingDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique code identifying this mapping.\nUse this code in the mappingCode parameter when uploading or confirming an import/export.\nPreset codes: 'limited-company-clients', 'individual-clients'.",
            "nullable": true,
            "example": "limited-company-clients"
          },
          "name": {
            "type": "string",
            "description": "Human-readable display name for this mapping.",
            "nullable": true,
            "example": "Limited Company"
          },
          "columnMappings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CsvColumnMappingDto"
            },
            "description": "The column mappings that define how CSV headers map to target fields.\nEach entry specifies a CSV header name and the corresponding client field.",
            "nullable": true
          },
          "matchField": {
            "$ref": "#/components/schemas/CsvImportMatchField"
          },
          "isPreset": {
            "type": "boolean",
            "description": "True if this is a preset mapping available to all tenants.\nPreset mappings cannot be modified or deleted.\nFalse for tenant-specific custom mappings.",
            "example": true
          },
          "mappingType": {
            "$ref": "#/components/schemas/CsvMappingType"
          },
          "createdDate": {
            "type": "string",
            "description": "When this mapping was created (UTC).",
            "format": "date-time",
            "example": "2024-01-15T10:30:00Z"
          },
          "updatedDate": {
            "type": "string",
            "description": "When this mapping was last updated (UTC). Null if never updated.",
            "format": "date-time",
            "nullable": true,
            "example": "2024-01-20T14:45:00Z"
          }
        },
        "additionalProperties": false,
        "description": "Represents a saved CSV mapping configuration.\nMappings define how CSV columns map to client fields and can be reused across imports and exports.\nPreset mappings are available to all tenants; tenant mappings are private."
      },
      "CsvMappingDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CsvMappingDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "CsvMappingSortField": {
        "enum": [
          "Name",
          "CreatedDate"
        ],
        "type": "string"
      },
      "CsvMappingType": {
        "enum": [
          "Client"
        ],
        "type": "string"
      },
      "CsvUploadResponseDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique code identifying this import job.\nUse this code to confirm and start the import via PUT /{code},\nor to check status via GET /{code}.",
            "nullable": true,
            "example": "csv-abc123"
          },
          "hasHeaderRow": {
            "type": "boolean",
            "description": "Whether the first row was treated as column headers.\nIf hasHeaderRow was explicitly provided in the request, this reflects that value.\nIf not provided, this shows the auto-detected result based on the first row content.",
            "example": true
          },
          "headers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of column headers detected from the CSV file.\nIf hasHeaderRow was true, these are from the first row.\nIf hasHeaderRow was false, these are auto-generated (Column1, Column2, etc.).",
            "nullable": true,
            "example": [
              "Company Name",
              "Company Number",
              "VAT Number",
              "Email"
            ]
          },
          "totalRows": {
            "type": "integer",
            "description": "Total number of data rows in the CSV file (excluding the header row if present).\nThis is the number of rows that will be processed during import.",
            "format": "int32",
            "example": 150
          },
          "previewRows": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": {
                "type": "string"
              }
            },
            "description": "Preview of the first few rows from the CSV file.\nEach row is a dictionary mapping header names to cell values.\nUse this to verify the data looks correct before confirming the import.\nTypically includes up to 5 preview rows.",
            "nullable": true
          },
          "suggestedMappings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CsvColumnMappingDto"
            },
            "description": "Auto-suggested column mappings based on header name matching.\nThe system attempts to match CSV headers to known target fields using fuzzy matching.\nReview and adjust these mappings as needed when confirming the import.\nOnly includes mappings for headers that could be matched to target fields.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response from uploading a CSV file with showPreview=true.\nContains a preview of the CSV data and auto-suggested column mappings.\nUse the code to call PUT /{code} to confirm mapping and start the import."
      },
      "CurrentUserResponse": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The user's unique code",
            "nullable": true
          },
          "email": {
            "type": "string",
            "description": "The user's email address",
            "nullable": true
          },
          "firstName": {
            "type": "string",
            "description": "The user's first name",
            "nullable": true
          },
          "lastName": {
            "type": "string",
            "description": "The user's last name",
            "nullable": true
          },
          "fullName": {
            "type": "string",
            "description": "The user's full name",
            "nullable": true
          },
          "isEmailVerified": {
            "type": "boolean",
            "description": "Indicates whether the user's email address has been verified"
          },
          "isSuperAdmin": {
            "type": "boolean",
            "description": "Indicates whether the user is a super admin"
          },
          "isSupportAgent": {
            "type": "boolean",
            "description": "Indicates whether the user is a support agent"
          },
          "avatar": {
            "type": "string",
            "description": "URL to the user's avatar image",
            "nullable": true
          },
          "authProvider": {
            "type": "string",
            "description": "The authentication provider type (Local, Auth0, Google, etc.)",
            "nullable": true
          },
          "utm": {
            "$ref": "#/components/schemas/UtmInfoDto"
          }
        },
        "additionalProperties": false,
        "description": "Response DTO for the current authenticated user"
      },
      "CustomFieldDataType": {
        "enum": [
          "Text",
          "Number",
          "Date",
          "Boolean",
          "Select",
          "MultiSelect",
          "TextArea",
          "Address",
          "Email",
          "File"
        ],
        "type": "string"
      },
      "CustomFieldDefinitionDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this custom field definition",
            "nullable": true
          },
          "label": {
            "type": "string",
            "description": "The display label shown to users for this field",
            "nullable": true
          },
          "entityType": {
            "$ref": "#/components/schemas/CustomFieldEntityType"
          },
          "dataType": {
            "$ref": "#/components/schemas/CustomFieldDataType"
          },
          "options": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The list of allowed options for Select and MultiSelect fields. Null for other data types.",
            "nullable": true
          },
          "clientTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientType"
            },
            "description": "The types of clients this custom field is applicable to.\nAn empty list means the field is applicable to all client types.",
            "nullable": true
          },
          "maxLength": {
            "type": "integer",
            "description": "Maximum character length for Text and TextArea types. Null means no limit.",
            "format": "int32",
            "nullable": true
          },
          "lines": {
            "type": "integer",
            "description": "Number of visible text lines for TextArea type. Null defaults to 3.",
            "format": "int32",
            "nullable": true
          },
          "displayWidth": {
            "$ref": "#/components/schemas/FieldDisplayWidth"
          },
          "booleanDisplayMode": {
            "$ref": "#/components/schemas/BooleanDisplayMode"
          },
          "customFieldGroupCode": {
            "type": "string",
            "description": "The code of the group this field belongs to",
            "nullable": true
          },
          "hasValues": {
            "type": "boolean",
            "description": "Whether any entities have values stored for this field. Only populated on detail responses.",
            "nullable": true
          },
          "isArchived": {
            "type": "boolean",
            "description": "Whether this custom field definition has been archived"
          },
          "sortOrder": {
            "type": "integer",
            "description": "The display order of this field relative to other custom fields",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Defines a custom field that can be attached to entities such as clients.\nCustom fields allow tenants to capture additional data beyond the built-in fields."
      },
      "CustomFieldDefinitionDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CustomFieldDefinitionDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "CustomFieldDefinitionSortField": {
        "enum": [
          "SortOrder",
          "Label"
        ],
        "type": "string"
      },
      "CustomFieldEntityType": {
        "enum": [
          "Client"
        ],
        "type": "string"
      },
      "CustomFieldGroupDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this custom field group",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The display name of this group",
            "nullable": true
          },
          "entityType": {
            "$ref": "#/components/schemas/CustomFieldEntityType"
          },
          "parentCustomFieldGroupCode": {
            "type": "string",
            "description": "The code of the parent group, or null if this is a root group",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "The display order of this group relative to other groups",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "A named group for organising custom field definitions.\nEach group renders as its own card on the entity detail page."
      },
      "CustomFieldGroupDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CustomFieldGroupDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "CustomFieldGroupSortField": {
        "enum": [
          "SortOrder",
          "Name"
        ],
        "type": "string"
      },
      "CustomFieldValueDto": {
        "type": "object",
        "properties": {
          "fieldCode": {
            "type": "string",
            "description": "The code of the CustomFieldDefinition this value belongs to",
            "nullable": true
          },
          "value": {
            "type": "string",
            "description": "The value of the custom field, stored as a string regardless of data type.\nFor Boolean fields use \"true\"/\"false\", for Date fields use ISO 8601 format,\nfor MultiSelect fields use a comma-separated list of selected options.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A custom field value for a client. Use the custom field definitions endpoint\nto retrieve data types, labels, and allowed options for each field code."
      },
      "CustomTokenDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this custom token",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Human-readable display name for the token (e.g. \"Company Secretary\")",
            "nullable": true
          },
          "tokenIdentifier": {
            "type": "string",
            "description": "The token identifier used in templates (e.g. \"CompanySecretary\" for {{ Custom.CompanySecretary }}).\nAlphanumeric with underscores only.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Optional prompt text shown when filling in the token value",
            "nullable": true
          },
          "defaultValue": {
            "type": "string",
            "description": "Optional default value pre-populated in the token form",
            "nullable": true
          },
          "displayWidth": {
            "type": "string",
            "description": "Preset display width for the input. Null defaults to Full.",
            "nullable": true
          },
          "lines": {
            "type": "integer",
            "description": "Number of visible text lines. Null renders a single-line input, 2+ renders a textarea.",
            "format": "int32",
            "nullable": true
          },
          "isRichText": {
            "type": "boolean",
            "description": "When true and Lines >= 2, the input renders as a rich text editor instead of a plain textarea."
          },
          "createdDate": {
            "type": "string",
            "description": "When the token was created",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "description": "When the token was last updated",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A user-defined custom token for document templates"
      },
      "CustomTokenDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CustomTokenDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "CustomTokenSortField": {
        "enum": [
          "Name"
        ],
        "type": "string"
      },
      "CustomerDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Platform-specific customer identifier (unique within the accounting platform)",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Customer/company name from the accounting platform",
            "nullable": true
          },
          "firstName": {
            "type": "string",
            "description": "Contact first name (if available from platform)",
            "nullable": true
          },
          "lastName": {
            "type": "string",
            "description": "Contact last name (if available from platform)",
            "nullable": true
          },
          "email": {
            "type": "string",
            "description": "Primary email address for the customer",
            "nullable": true
          },
          "contactNumber": {
            "type": "string",
            "description": "Primary contact phone number",
            "nullable": true
          },
          "isActive": {
            "type": "boolean",
            "description": "Whether the customer is active in the accounting platform"
          },
          "externalUrl": {
            "type": "string",
            "description": "Direct link to view the customer in the accounting platform",
            "nullable": true
          },
          "outstandingBalance": {
            "type": "number",
            "description": "Outstanding amount owed by the customer",
            "format": "double",
            "nullable": true
          },
          "overdueBalance": {
            "type": "number",
            "description": "Overdue amount owed by the customer",
            "format": "double",
            "nullable": true
          },
          "totalInvoiced": {
            "type": "number",
            "description": "Total amount invoiced to the customer (sum of all invoices)",
            "format": "double",
            "nullable": true
          },
          "platformData": {
            "type": "object",
            "additionalProperties": {},
            "description": "Platform-specific data that doesn't fit into the common model",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Customer data retrieved from third-party accounting platforms (Xero, QuickBooks, FreeAgent, etc.).\nRepresents a customer/client as stored in the accounting system, including contact details and financial balances.\nUsed for importing clients and syncing financial data."
      },
      "DataFormAnswerDto": {
        "type": "object",
        "properties": {
          "dataFormQuestionCode": {
            "type": "string",
            "description": "The code of the form question this answer belongs to",
            "nullable": true
          },
          "value": {
            "type": "string",
            "description": "The submitted answer value",
            "nullable": true
          },
          "reviewStatus": {
            "$ref": "#/components/schemas/DataFormAnswerReviewStatus"
          },
          "previousValue": {
            "type": "string",
            "description": "The client field's value at the time the form was submitted",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "An individual answer to a form question"
      },
      "DataFormAnswerReviewStatus": {
        "enum": [
          "Pending",
          "Accepted",
          "Rejected"
        ],
        "type": "string"
      },
      "DataFormCategoryDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this form category",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The display name of the form category",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A grouping used to classify forms"
      },
      "DataFormCategoryDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DataFormCategoryDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "DataFormCategorySortField": {
        "enum": [
          "Name"
        ],
        "type": "string"
      },
      "DataFormDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Stable identifier. For library-shipped items this is the library code; for tenant-imported\nitems this is the tenant entity's own code.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name shown to users in lists, dialogs, and the import browser.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Optional human-readable summary of what this entity is for.",
            "nullable": true
          },
          "libraryCode": {
            "type": "string",
            "description": "The Code of the library template this entity was imported from, or null if the entity\nis not from the library. Read-only — cannot be changed once set. Example: \"vat_returns\".",
            "nullable": true
          },
          "libraryStatus": {
            "$ref": "#/components/schemas/LibraryStatus"
          },
          "isImported": {
            "type": "boolean",
            "description": "True if the tenant has already imported this library item."
          },
          "deprecated": {
            "type": "boolean",
            "description": "True if this library item has been retired. Deprecated items are hidden from the import\nbrowser (so new tasks cannot be created from them) but remain available for revert-to-library\non existing imports."
          },
          "introduction": {
            "type": "string",
            "description": "Introductory text shown at the top of the form when displayed to clients",
            "nullable": true
          },
          "category": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "status": {
            "$ref": "#/components/schemas/DataFormStatus"
          },
          "defaultMessage": {
            "type": "string",
            "description": "Default message included in the notification email when this form is sent to a client",
            "nullable": true
          },
          "responseCount": {
            "type": "integer",
            "description": "Number of requests that have received a response. Used to warn when editing a form that has been used.",
            "format": "int32"
          },
          "sections": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DataFormSectionDto"
            },
            "description": "The sections and questions belonging to this form. Only populated on detail (GetByCode) responses.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A custom form definition (list view)"
      },
      "DataFormDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DataFormDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "DataFormPreviewDto": {
        "type": "object",
        "properties": {
          "dataFormName": {
            "type": "string",
            "nullable": true
          },
          "introduction": {
            "type": "string",
            "description": "Introductory text shown at the top of the form",
            "nullable": true
          },
          "sections": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DataFormPreviewSectionDto"
            },
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Preview of a form as the client would see it (sections + questions, no internal metadata)"
      },
      "DataFormPreviewQuestionDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "nullable": true
          },
          "prompt": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "dataType": {
            "$ref": "#/components/schemas/CustomFieldDataType"
          },
          "options": {
            "type": "string",
            "nullable": true
          },
          "maxLength": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "lines": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "displayWidth": {
            "$ref": "#/components/schemas/FieldDisplayWidth"
          },
          "booleanDisplayMode": {
            "$ref": "#/components/schemas/BooleanDisplayMode"
          },
          "isRequired": {
            "type": "boolean"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          }
        },
        "additionalProperties": false
      },
      "DataFormPreviewSectionDto": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "nullable": true
          },
          "introduction": {
            "type": "string",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          },
          "questions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DataFormPreviewQuestionDto"
            },
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "DataFormQuestionDto": {
        "required": [
          "prompt"
        ],
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Stable identifier for this question, used to key answers",
            "nullable": true
          },
          "prompt": {
            "maxLength": 4000,
            "minLength": 1,
            "type": "string",
            "description": "The question text shown to the client"
          },
          "description": {
            "type": "string",
            "description": "An optional hint or clarification shown beneath the prompt",
            "nullable": true
          },
          "longDescription": {
            "type": "string",
            "description": "Optional rich-text long description shown as a tooltip on the form",
            "nullable": true
          },
          "questionType": {
            "$ref": "#/components/schemas/DataFormQuestionType"
          },
          "clientField": {
            "$ref": "#/components/schemas/ClientCsvTargetField"
          },
          "customFieldDefinition": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "dataType": {
            "$ref": "#/components/schemas/CustomFieldDataType"
          },
          "options": {
            "type": "string",
            "description": "JSON array of selectable options for Select/MultiSelect data types",
            "nullable": true
          },
          "maxLength": {
            "type": "integer",
            "description": "Maximum character length for Text and TextArea types",
            "format": "int32",
            "nullable": true
          },
          "lines": {
            "type": "integer",
            "description": "Number of visible text lines for TextArea type",
            "format": "int32",
            "nullable": true
          },
          "displayWidth": {
            "$ref": "#/components/schemas/FieldDisplayWidth"
          },
          "booleanDisplayMode": {
            "$ref": "#/components/schemas/BooleanDisplayMode"
          },
          "isRequired": {
            "type": "boolean",
            "description": "When true, the client must answer this question before submitting the form"
          },
          "sortOrder": {
            "type": "integer",
            "description": "The display order of this question relative to others in the section",
            "format": "int32"
          },
          "condition": {
            "$ref": "#/components/schemas/ConditionDto"
          }
        },
        "additionalProperties": false,
        "description": "A question within a form section"
      },
      "DataFormQuestionType": {
        "enum": [
          "ClientField",
          "CustomField",
          "DataFormSpecific"
        ],
        "type": "string"
      },
      "DataFormRequestDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this form request",
            "nullable": true
          },
          "dataForm": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "client": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "status": {
            "$ref": "#/components/schemas/DataFormRequestStatus"
          },
          "submittedAt": {
            "type": "string",
            "description": "The date and time the client submitted their answers, if submitted",
            "format": "date-time",
            "nullable": true
          },
          "submittedByEmail": {
            "type": "string",
            "description": "Email address of the recipient who submitted (from magic link token).",
            "nullable": true
          },
          "notifyUser": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "autoAcceptData": {
            "type": "boolean",
            "description": "When true, submitted data is automatically accepted and copied to the client record without manual review"
          },
          "message": {
            "type": "string",
            "description": "A message from the sender explaining what the client needs to do",
            "nullable": true
          },
          "sentToEmails": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The email addresses the form notification was sent to",
            "nullable": true
          },
          "sentAt": {
            "type": "string",
            "description": "When the notification email was sent",
            "format": "date-time",
            "nullable": true
          },
          "magicLinkToken": {
            "type": "string",
            "description": "The magic link token for this request. Only populated on detail responses for pending requests.",
            "format": "uuid",
            "nullable": true
          },
          "answers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DataFormAnswerDto"
            },
            "description": "The submitted answers. Only populated on detail (GetByCode) responses.",
            "nullable": true
          },
          "pendingReviewCount": {
            "type": "integer",
            "description": "Number of answers still awaiting review (ReviewStatus = Pending)",
            "format": "int32"
          },
          "task": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "taskCategory": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "lastChasedDate": {
            "type": "string",
            "description": "When this form request was last chased. Null if never chased.",
            "format": "date-time",
            "nullable": true
          },
          "chaseFrequencyDays": {
            "type": "integer",
            "description": "How often (in days) this form request is chased. Null means chasing is disabled.",
            "format": "int32",
            "nullable": true
          },
          "nextChaseDate": {
            "type": "string",
            "description": "When this form request is next due for chasing.",
            "format": "date-time",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "The date and time this request was created (i.e. sent to the client)",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "A form request sent to a client"
      },
      "DataFormRequestDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DataFormRequestDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "DataFormRequestSortField": {
        "enum": [
          "CreatedDate",
          "Status"
        ],
        "type": "string"
      },
      "DataFormRequestStatus": {
        "enum": [
          "PendingResponse",
          "ResponseReceived"
        ],
        "type": "string"
      },
      "DataFormSectionDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Stable identifier for this section, used to match across saves",
            "nullable": true
          },
          "title": {
            "type": "string",
            "description": "The display title of the section",
            "nullable": true
          },
          "introduction": {
            "type": "string",
            "description": "Introductory text shown to clients at the top of this section.",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "The display order of this section relative to others in the form",
            "format": "int32"
          },
          "condition": {
            "$ref": "#/components/schemas/ConditionDto"
          },
          "clientTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientType"
            },
            "description": "The types of clients this section is applicable to.\nAn empty list means the section is shown to all client types.",
            "nullable": true
          },
          "questions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DataFormQuestionDto"
            },
            "description": "The questions belonging to this section, in display order",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A section within a form"
      },
      "DataFormSortField": {
        "enum": [
          "Name",
          "Status"
        ],
        "type": "string"
      },
      "DataFormStatus": {
        "enum": [
          "Draft",
          "Published",
          "Archived"
        ],
        "type": "string"
      },
      "DaysBeforeOrAfter": {
        "enum": [
          "OnActualDate",
          "DaysBefore",
          "DaysAfter"
        ],
        "type": "string"
      },
      "DeadlineComplianceReportDto": {
        "type": "object",
        "properties": {
          "summary": {
            "$ref": "#/components/schemas/DeadlineComplianceSummaryDto"
          },
          "rows": {
            "$ref": "#/components/schemas/DeadlineComplianceRowDtoPagedResult"
          },
          "upcomingDeadlines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UpcomingDeadlineBucketDto"
            },
            "description": "The forward-looking pipeline: open tasks with the chosen deadline, counted into\ndays-remaining buckets. Entity filters apply; the date window does not. Always all five\nbuckets, zero-filled, nearest first (overdue, 0-7, 8-14, 15-30, 31+).",
            "nullable": true
          },
          "generatedAt": {
            "type": "string",
            "description": "When the report was generated (UTC).",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "The Deadline Compliance report: which deadlines did we miss, and which are we about to?\nThe cohort is every non-Skipped task whose chosen deadline (due or statutory) fell in the\nwindow - so misses that are still open count, unlike a completion-anchored view."
      },
      "DeadlineComplianceRowDto": {
        "type": "object",
        "properties": {
          "groupKind": {
            "$ref": "#/components/schemas/ReportGroupKind"
          },
          "groupCode": {
            "type": "string",
            "description": "Entity code or month key (\"yyyy-MM\"). Null for null buckets.",
            "nullable": true
          },
          "groupName": {
            "type": "string",
            "description": "Display name for the group.",
            "nullable": true
          },
          "deadlineCount": {
            "type": "integer",
            "description": "Deadlines that fell in the window for this group.",
            "format": "int32"
          },
          "metCount": {
            "type": "integer",
            "description": "Deadlines met: task completed on or before the deadline.",
            "format": "int32"
          },
          "lateCount": {
            "type": "integer",
            "description": "Deadlines missed but recovered: task completed after the deadline.",
            "format": "int32"
          },
          "missedOpenCount": {
            "type": "integer",
            "description": "Deadlines missed and still open.",
            "format": "int32"
          },
          "pendingCount": {
            "type": "integer",
            "description": "Deadlines not yet reached, task still open - excluded from the compliance rate.",
            "format": "int32"
          },
          "compliancePct": {
            "type": "number",
            "description": "Met as a percentage of this group's decided deadlines. Null when nothing decided.",
            "format": "double",
            "nullable": true
          },
          "avgDaysLate": {
            "type": "number",
            "description": "Average days late across this group's misses. Null when there are no misses.",
            "format": "double",
            "nullable": true
          },
          "worstDaysLate": {
            "type": "integer",
            "description": "Days late of this group's worst miss. Null when there are no misses.",
            "format": "int32",
            "nullable": true
          },
          "worstTask": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          }
        },
        "additionalProperties": false,
        "description": "One row of the Deadline Compliance breakdown table."
      },
      "DeadlineComplianceRowDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DeadlineComplianceRowDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "DeadlineComplianceSummaryDto": {
        "type": "object",
        "properties": {
          "deadlineCount": {
            "type": "integer",
            "description": "Deadlines that fell in the window (Skipped tasks excluded).",
            "format": "int32"
          },
          "metCount": {
            "type": "integer",
            "description": "Deadlines met: task completed on or before the deadline.",
            "format": "int32"
          },
          "lateCount": {
            "type": "integer",
            "description": "Deadlines missed but recovered: task completed after the deadline.",
            "format": "int32"
          },
          "missedOpenCount": {
            "type": "integer",
            "description": "Deadlines missed and still open - the actionable misses.",
            "format": "int32"
          },
          "pendingCount": {
            "type": "integer",
            "description": "Deadlines in the window not yet reached, task still open - undecided, excluded from the\ncompliance rate. Only non-zero for windows that extend into the future.",
            "format": "int32"
          },
          "compliancePct": {
            "type": "number",
            "description": "Met as a percentage of decided deadlines (met + late + missed-open). Null when nothing\nhas been decided yet.",
            "format": "double",
            "nullable": true
          },
          "avgDaysLate": {
            "type": "number",
            "description": "Average days late across misses (late completions measured to completion, open misses to\ntoday). Null when there are no misses.",
            "format": "double",
            "nullable": true
          },
          "worstDaysLate": {
            "type": "integer",
            "description": "Days late of the worst miss. Null when there are no misses.",
            "format": "int32",
            "nullable": true
          },
          "worstTask": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          }
        },
        "additionalProperties": false,
        "description": "Headline KPIs for the Deadline Compliance report. Every cohort task lands in exactly one\nof Met / Late / MissedOpen / Pending."
      },
      "DeadlineReferenceType": {
        "enum": [
          "DueDate",
          "StartDate"
        ],
        "type": "string"
      },
      "DesignThemeDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique identifier for the design theme",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name for the theme (e.g., \"Professional Blue\", \"Corporate Standard\")",
            "nullable": true
          },
          "isDefault": {
            "type": "boolean",
            "description": "Whether this is the default theme for the tenant. Only one theme per tenant should be marked as default."
          },
          "heading1": {
            "$ref": "#/components/schemas/FontSettingsDto"
          },
          "heading2": {
            "$ref": "#/components/schemas/FontSettingsDto"
          },
          "heading3": {
            "$ref": "#/components/schemas/FontSettingsDto"
          },
          "body": {
            "$ref": "#/components/schemas/FontSettingsDto"
          },
          "tableHeader": {
            "$ref": "#/components/schemas/FontSettingsDto"
          },
          "tableCell": {
            "$ref": "#/components/schemas/FontSettingsDto"
          },
          "logoUrl": {
            "type": "string",
            "description": "URL to the company logo image (used in document headers)",
            "nullable": true
          },
          "primaryColor": {
            "type": "string",
            "description": "Primary brand color in hex format (used for main headings and borders)",
            "nullable": true
          },
          "secondaryColor": {
            "type": "string",
            "description": "Secondary brand color in hex format (used for subheadings)",
            "nullable": true
          },
          "accentColor": {
            "type": "string",
            "description": "Accent color in hex format (used for highlights and calls to action)",
            "nullable": true
          },
          "backgroundColor": {
            "type": "string",
            "description": "Optional page background color in hex format. When null, no background-color is applied.",
            "nullable": true
          },
          "linkColor": {
            "type": "string",
            "description": "Optional link color in hex format. When null, links inherit default text color.",
            "nullable": true
          },
          "linkHoverColor": {
            "type": "string",
            "description": "Optional link hover color in hex format. When null, no hover color change.",
            "nullable": true
          },
          "primaryButton": {
            "$ref": "#/components/schemas/ButtonStyleDto"
          },
          "secondaryButton": {
            "$ref": "#/components/schemas/ButtonStyleDto"
          },
          "navBackgroundColor": {
            "type": "string",
            "description": "Navigation background color for the client portal (e.g., \"#1e293b\")",
            "nullable": true
          },
          "navTextColor": {
            "type": "string",
            "description": "Navigation text color for the client portal",
            "nullable": true
          },
          "navActiveBackgroundColor": {
            "type": "string",
            "description": "Active navigation item highlight color (supports rgba, e.g., \"rgba(255,255,255,0.15)\")",
            "nullable": true
          },
          "navActiveTextColor": {
            "type": "string",
            "description": "Active navigation item text color",
            "nullable": true
          },
          "cardBackgroundColor": {
            "type": "string",
            "description": "Card/panel background color in the content area",
            "nullable": true
          },
          "borderRadius": {
            "type": "integer",
            "description": "Global corner radius in pixels for cards, buttons, and inputs",
            "format": "int32",
            "nullable": true
          },
          "navFontSize": {
            "type": "number",
            "description": "Font size in points for the client portal navigation bar. Null falls back to body font size.",
            "format": "float",
            "nullable": true
          },
          "faviconUrl": {
            "type": "string",
            "description": "URL to a tenant-specific favicon for the client portal",
            "nullable": true
          },
          "pageMargins": {
            "$ref": "#/components/schemas/MarginsDto"
          },
          "headerTextContentBlock": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "headerPageSelection": {
            "$ref": "#/components/schemas/PageSelection"
          },
          "footerContentBlock": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "footerPageSelection": {
            "$ref": "#/components/schemas/PageSelection"
          },
          "pageNumberDisplay": {
            "$ref": "#/components/schemas/PageSelection"
          },
          "customCSS": {
            "type": "string",
            "description": "Additional custom CSS rules for advanced styling beyond the standard options",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "When this theme was created",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "description": "When this theme was last updated",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "Complete visual styling and branding configuration for generated documents (proposals, engagement letters, reports, etc.).\nDefines typography, colors, layout, headers, footers, and custom CSS to ensure consistent professional branding.\nDesign themes can be applied to document templates to control the appearance of generated PDFs and HTML documents."
      },
      "DesignThemeDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DesignThemeDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "DesignThemeSortField": {
        "enum": [
          "Name"
        ],
        "type": "string"
      },
      "DetectedServiceDto": {
        "type": "object",
        "properties": {
          "csvServiceName": {
            "type": "string",
            "description": "Display name of the detected service (e.g., \"SA100\", \"A/Cs\", \"A/Cs (2)\")",
            "nullable": true
          },
          "clientCount": {
            "type": "integer",
            "description": "Number of rows with a non-empty fee value for this service",
            "format": "int32"
          },
          "feeColumnIndex": {
            "type": "integer",
            "description": "The column index of the fee column for this service in the CSV.\nUsed to identify the correct column when headers are duplicated.",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "A service detected from the CSV headers during analysis"
      },
      "DirectDebitSettingsDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique identifier for the settings",
            "nullable": true
          },
          "requestEmailContentBlock": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          }
        },
        "additionalProperties": false,
        "description": "Tenant-level configuration for direct debit request behavior and email settings.\nControls how direct debit requests are sent to clients."
      },
      "DocumentApprovalExecutionStateDto": {
        "type": "object",
        "properties": {
          "documentCode": {
            "type": "string",
            "description": "The code of the document sent for client approval.",
            "nullable": true
          },
          "clientCode": {
            "type": "string",
            "description": "The client code the document belongs to.",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "description": "UTC timestamp of when the document was linked to this step.",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "Execution state for a DocumentApproval workflow step.\nContains information about the document sent for client approval.\nRead-only - written by the system during step execution, never edited by users."
      },
      "DocumentApprovalStepConfigDto": {
        "type": "object",
        "properties": {
          "title": {
            "maxLength": 500,
            "type": "string",
            "description": "Optional default title for the document.\nPre-fills the upload form so the user only needs to select the file.",
            "nullable": true
          },
          "summary": {
            "maxLength": 2000,
            "type": "string",
            "description": "Optional default summary for the document.\nPre-fills the upload form so the user only needs to select the file.",
            "nullable": true
          },
          "categoryCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Optional default document category code.\nPre-fills the category dropdown on the upload form.",
            "nullable": true
          },
          "recipientContactTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientContactType"
            },
            "description": "Client contact types to send the approval request email to.\nResolved at execution time from the task's associated client contacts.",
            "nullable": true
          },
          "additionalEmailAddresses": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Static email addresses to send the approval request email to.",
            "nullable": true
          },
          "chaseFrequencyDays": {
            "type": "integer",
            "description": "Override for how often (in days) to chase this approval.\nWhen null, the tenant-level default is used.",
            "format": "int32",
            "nullable": true
          },
          "documentTemplate": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "designThemeCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Optional design theme override for PDF generation.\nWhen null, uses the template's default theme.",
            "nullable": true
          },
          "templateTokenValues": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Token values for template rendering, keyed by token name\n(e.g. \"Title\", \"Subtitle\", \"Custom.CompanySecretary\").\nCollected at workflow design time, applied at execution time.",
            "nullable": true
          },
          "portalFolderPath": {
            "maxLength": 500,
            "type": "string",
            "description": "Portal folder path for the generated document.\nWhen null, defaults to \"Generated Documents\".",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Configuration for DocumentApproval workflow steps.\nUsed for both workflow template definition and task workflow step instance customization."
      },
      "DocumentCategoryDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this document category",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The display name of the document category",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "The sort order for displaying document categories",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "A tenant-defined grouping used to classify client documents"
      },
      "DocumentCategoryDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DocumentCategoryDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "DocumentCategorySortField": {
        "enum": [
          "SortOrder",
          "Name"
        ],
        "type": "string"
      },
      "DocumentRequestDetailDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique code for this document request",
            "nullable": true
          },
          "client": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "title": {
            "type": "string",
            "description": "Title describing what documents are needed",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Detailed description of what is needed",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/DocumentRequestStatus"
          },
          "deadline": {
            "type": "string",
            "description": "Optional deadline for the client to respond by",
            "format": "date",
            "nullable": true
          },
          "documentCount": {
            "type": "integer",
            "description": "Number of documents attached to this request",
            "format": "int32"
          },
          "notifyUser": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "createdByUser": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "task": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "taskCategory": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "createdDate": {
            "type": "string",
            "description": "When the request was created",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "description": "When the request was last updated",
            "format": "date-time",
            "nullable": true
          },
          "lastChasedDate": {
            "type": "string",
            "description": "When this request was last chased. Null if never chased.",
            "format": "date-time",
            "nullable": true
          },
          "chaseFrequencyDays": {
            "type": "integer",
            "description": "How often (in days) this request is chased. Null means chasing is disabled.",
            "format": "int32",
            "nullable": true
          },
          "nextChaseDate": {
            "type": "string",
            "description": "When this request is next due for chasing.",
            "format": "date-time",
            "nullable": true
          },
          "documents": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientDocumentDto"
            },
            "description": "Documents attached to this request",
            "nullable": true
          },
          "responses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DocumentRequestResponseDto"
            },
            "description": "Submission responses for this request",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Detailed response DTO for a document request, including documents and responses"
      },
      "DocumentRequestDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique code for this document request",
            "nullable": true
          },
          "client": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "title": {
            "type": "string",
            "description": "Title describing what documents are needed",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Detailed description of what is needed",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/DocumentRequestStatus"
          },
          "deadline": {
            "type": "string",
            "description": "Optional deadline for the client to respond by",
            "format": "date",
            "nullable": true
          },
          "documentCount": {
            "type": "integer",
            "description": "Number of documents attached to this request",
            "format": "int32"
          },
          "notifyUser": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "createdByUser": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "task": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "taskCategory": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "createdDate": {
            "type": "string",
            "description": "When the request was created",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "description": "When the request was last updated",
            "format": "date-time",
            "nullable": true
          },
          "lastChasedDate": {
            "type": "string",
            "description": "When this request was last chased. Null if never chased.",
            "format": "date-time",
            "nullable": true
          },
          "chaseFrequencyDays": {
            "type": "integer",
            "description": "How often (in days) this request is chased. Null means chasing is disabled.",
            "format": "int32",
            "nullable": true
          },
          "nextChaseDate": {
            "type": "string",
            "description": "When this request is next due for chasing.",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response DTO for a document request"
      },
      "DocumentRequestDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DocumentRequestDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "DocumentRequestExecutionStateDto": {
        "type": "object",
        "properties": {
          "documentRequestCode": {
            "type": "string",
            "description": "The code of the created document request.",
            "nullable": true
          },
          "clientCode": {
            "type": "string",
            "description": "The client code the document request was created for.",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "description": "UTC timestamp of when the document request was created and opened.",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "Execution state for a DocumentRequest workflow step.\nContains information about the created document request after execution.\nRead-only - written by the system during step execution, never edited by users."
      },
      "DocumentRequestRejectAction": {
        "enum": [
          "Reopen",
          "ReopenClearDocs"
        ],
        "type": "string"
      },
      "DocumentRequestResponseDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique code for this response",
            "nullable": true
          },
          "comments": {
            "type": "string",
            "description": "Comments provided with the submission",
            "nullable": true
          },
          "submittedByUser": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "submittedByContact": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "submittedByEmail": {
            "type": "string",
            "description": "Email address of the recipient who submitted (from magic link token).",
            "nullable": true
          },
          "submittedDate": {
            "type": "string",
            "description": "When this response was submitted",
            "format": "date-time"
          },
          "reviewedByUser": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "reviewedDate": {
            "type": "string",
            "description": "When this response was reviewed",
            "format": "date-time",
            "nullable": true
          },
          "reviewStatus": {
            "$ref": "#/components/schemas/DocumentRequestResponseStatus"
          },
          "reviewNote": {
            "type": "string",
            "description": "Note provided by the reviewer",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "When this response was created",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "Response DTO for a document request submission/response"
      },
      "DocumentRequestResponseStatus": {
        "enum": [
          "Pending",
          "Accepted",
          "Rejected"
        ],
        "type": "string"
      },
      "DocumentRequestSortField": {
        "enum": [
          "Title",
          "Status",
          "CreatedDate",
          "Deadline"
        ],
        "type": "string"
      },
      "DocumentRequestStatus": {
        "enum": [
          "Draft",
          "Open",
          "Submitted",
          "Accepted",
          "Rejected"
        ],
        "type": "string"
      },
      "DocumentRequestStepConfigDto": {
        "required": [
          "title"
        ],
        "type": "object",
        "properties": {
          "title": {
            "maxLength": 500,
            "minLength": 1,
            "type": "string",
            "description": "The title for the document request to create.\nDescribes what documents are being requested from the client."
          },
          "description": {
            "type": "string",
            "description": "Optional description providing details about what documents are needed.",
            "nullable": true
          },
          "deadlineDaysFromExecution": {
            "maximum": 365,
            "minimum": 1,
            "type": "integer",
            "description": "Number of days from step execution to set as the client-facing deadline.\nFor example, 14 means the client has 14 days from when the step runs.\nNull means no deadline is set on the document request.",
            "format": "int32",
            "nullable": true
          },
          "notifyUserCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Code of the user to notify when the client submits a response.\nDefaults to the step's assigned user at execution time. Only set this\nto override the default — most workflows should leave it null.",
            "nullable": true
          },
          "recipientContactTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientContactType"
            },
            "description": "Client contact types to send the document request email to.\nResolved at execution time from the task's associated client contacts.",
            "nullable": true
          },
          "additionalEmailAddresses": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Static email addresses to send the document request email to.",
            "nullable": true
          },
          "chaseFrequencyDays": {
            "type": "integer",
            "description": "Override for how often (in days) to chase this document request.\nWhen null, the tenant-level default is used.",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Configuration for DocumentRequest workflow steps.\nUsed for both workflow template definition and task workflow step instance customization."
      },
      "DocumentTemplateDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Stable identifier. For library-shipped items this is the library code; for tenant-imported\nitems this is the tenant entity's own code.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name shown to users in lists, dialogs, and the import browser.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Optional human-readable summary of what this entity is for.",
            "nullable": true
          },
          "libraryCode": {
            "type": "string",
            "description": "The Code of the library template this entity was imported from, or null if the entity\nis not from the library. Read-only — cannot be changed once set. Example: \"vat_returns\".",
            "nullable": true
          },
          "libraryStatus": {
            "$ref": "#/components/schemas/LibraryStatus"
          },
          "isImported": {
            "type": "boolean",
            "description": "True if the tenant has already imported this library item."
          },
          "deprecated": {
            "type": "boolean",
            "description": "True if this library item has been retired. Deprecated items are hidden from the import\nbrowser (so new tasks cannot be created from them) but remain available for revert-to-library\non existing imports."
          },
          "type": {
            "$ref": "#/components/schemas/TemplateType"
          },
          "bodyHtml": {
            "type": "string",
            "description": "The template content using Liquid/Fluid syntax with variables ({{ client.Name }}),\nloops ({% for %}), conditionals ({% if %}), and content block references",
            "nullable": true
          },
          "outputNameTemplate": {
            "type": "string",
            "description": "Optional template for naming rendered documents using {{ token }} placeholders.\nWhen null, documents use the template's Name.",
            "nullable": true
          },
          "isActive": {
            "type": "boolean",
            "description": "Whether this template is available for use (inactive templates are hidden but preserved)"
          },
          "defaultDesignTheme": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "createdDate": {
            "type": "string",
            "description": "When this template was created",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "description": "When this template was last updated",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Reusable document template for generating HTML documents such as proposals, engagement letters, reports, and invoices.\nTemplates use Liquid/Fluid syntax for dynamic content, variables, loops, and conditionals.\nCan reference content blocks and be styled with design themes for consistent branding."
      },
      "DocumentTemplateDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DocumentTemplateDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "DocumentTemplateSortField": {
        "enum": [
          "Name",
          "UpdatedDate"
        ],
        "type": "string"
      },
      "DocumentTemplateTokenInfo": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The token key used for form values (e.g. \"Title\", \"Custom.InvoiceRef\")",
            "nullable": true
          },
          "label": {
            "type": "string",
            "description": "Human-readable display label for the token (e.g. \"Invoice Ref\").\nFalls back to Name if not set.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Optional description/prompt text for the token (from custom token definition)",
            "nullable": true
          },
          "defaultValue": {
            "type": "string",
            "description": "Optional default value for the token (from custom token definition)",
            "nullable": true
          },
          "isCustomToken": {
            "type": "boolean",
            "description": "Whether this token is a user-defined custom token (Custom.* prefix)"
          },
          "displayWidth": {
            "type": "string",
            "description": "Preset display width for the input (from custom token definition). Null defaults to Full.",
            "nullable": true
          },
          "lines": {
            "type": "integer",
            "description": "Number of visible text lines (from custom token definition). Null renders a single-line input.",
            "format": "int32",
            "nullable": true
          },
          "isRichText": {
            "type": "boolean",
            "description": "When true, the input renders as a rich text editor. The value will contain HTML."
          }
        },
        "additionalProperties": false,
        "description": "Information about a token found in a document template,\nincluding metadata from custom token definitions when available."
      },
      "DueDateConfigDto": {
        "type": "object",
        "properties": {
          "type": {
            "$ref": "#/components/schemas/DueDateType"
          },
          "intervalValue": {
            "type": "integer",
            "description": "Numeric value for the interval. Required when Type is RelativeToStart (Due is set this many\nunits after the Start) or RelativeToStatutory (Due is set this many units before the Statutory date).",
            "format": "int32",
            "nullable": true
          },
          "intervalUnit": {
            "$ref": "#/components/schemas/RecurrenceUnit"
          },
          "fixedMonth": {
            "type": "integer",
            "description": "Month (1-12). Required when Type is SpecificDate.",
            "format": "int32",
            "nullable": true
          },
          "fixedDay": {
            "type": "integer",
            "description": "Day of month (1-31). Required when Type is SpecificDate. Clamped to last day of month at projection time.",
            "format": "int32",
            "nullable": true
          },
          "clientDateSourceType": {
            "$ref": "#/components/schemas/ClientDateSourceType"
          },
          "clientDateType": {
            "$ref": "#/components/schemas/ClientDateType"
          },
          "customFieldDefinitionCode": {
            "type": "string",
            "description": "Custom field code. Required when Type is ClientKeyDate and ClientDateSourceType is CustomField.",
            "nullable": true
          },
          "customFieldDefinitionLabel": {
            "type": "string",
            "description": "Custom field label. Populated in responses only.",
            "nullable": true
          },
          "timing": {
            "$ref": "#/components/schemas/DaysBeforeOrAfter"
          },
          "offsetDays": {
            "type": "integer",
            "description": "Number of days before or after the client date. Required when Type is ClientKeyDate.\nPaired with OffsetMonths for composite offsets like \"9 months + 1 day\" (CT payment).",
            "format": "int32",
            "nullable": true
          },
          "offsetMonths": {
            "type": "integer",
            "description": "Number of months before or after the client date. Paired with OffsetDays. NULL when no months\nportion is needed. Used when Type is ClientKeyDate.",
            "format": "int32",
            "nullable": true
          },
          "dayOfMonth": {
            "type": "integer",
            "description": "Day of month (1-31). Required when Type is DayOfMonth. Clamped to end-of-month for shorter\nmonths (e.g. 31 -> 28 in non-leap February). Requires monthly cadence.",
            "format": "int32",
            "nullable": true
          },
          "monthDayPatterns": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WeekDayPatternDto"
            },
            "description": "Positional weekday patterns within each occurrence's month. Required when Type is MonthDay.\nExample: [{ Position: \"First\", Day: \"Monday\" }, { Position: \"Last\", Day: \"Friday\" }].\nRequires monthly or yearly cadence.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Configuration for the projected DueDate on tasks created from a recurring task.\nDifferent properties are required based on the Type value:\n- RelativeToStart: IntervalValue + IntervalUnit (e.g., 2 weeks after StartDate)\n- SpecificDate: FixedMonth + FixedDay (DD/MM annual; invalid days clamped to end-of-month)\n- ClientKeyDate: ClientDateSourceType + Timing + OffsetDays + OffsetMonths, plus ClientDateType (KeyDate) or CustomFieldDefinitionCode (CustomField)\n- DayOfMonth: DayOfMonth (1-31, clamped to end-of-month for shorter months) - requires monthly cadence\n- MonthDay: MonthDayPatterns (positional weekday list, e.g. First Monday) - requires monthly/yearly cadence\n- RelativeToStatutory: IntervalValue + IntervalUnit (Due = Statutory - interval) - requires TaskDateBasis=StatutoryDate"
      },
      "DueDateType": {
        "enum": [
          "RelativeToStart",
          "SpecificDate",
          "ClientKeyDate",
          "DayOfMonth",
          "MonthDay",
          "RelativeToStatutory"
        ],
        "type": "string"
      },
      "EmailAttachmentDto": {
        "required": [
          "contentType",
          "fileName"
        ],
        "type": "object",
        "properties": {
          "fileName": {
            "minLength": 1,
            "type": "string",
            "description": "File name"
          },
          "contentType": {
            "minLength": 1,
            "type": "string",
            "description": "MIME content type"
          },
          "contentBase64": {
            "type": "string",
            "description": "Base64 encoded file content (Option 1)",
            "nullable": true
          },
          "url": {
            "type": "string",
            "description": "URL to download attachment from (Option 2)",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Email attachment DTO"
      },
      "EmailAttachmentInfoDto": {
        "type": "object",
        "properties": {
          "uniqueId": {
            "type": "string",
            "description": "Unique attachment identifier",
            "format": "uuid"
          },
          "fileName": {
            "type": "string",
            "description": "File name",
            "nullable": true
          },
          "contentType": {
            "type": "string",
            "description": "MIME content type",
            "nullable": true
          },
          "size": {
            "type": "integer",
            "description": "File size in bytes",
            "format": "int64",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Email attachment information DTO (for responses)"
      },
      "EmailBroadcastAudienceRequest": {
        "type": "object",
        "properties": {
          "savedViewCode": {
            "maxLength": 100,
            "type": "string",
            "description": "The code of a saved client view whose filter selects which clients to include.\nMutually exclusive with Filter.",
            "nullable": true,
            "example": "active-limited-companies"
          },
          "filter": {
            "$ref": "#/components/schemas/EmailBroadcastFilterDto"
          },
          "excludedClientCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Client codes to exclude from the filter results.",
            "nullable": true
          },
          "additionalClientCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Hand-picked client codes to add on top of the filter results.",
            "nullable": true
          },
          "allContacts": {
            "type": "boolean",
            "description": "When true, every contact of each client with an email address is a To recipient.\nPart of the optional To-recipient configuration used to count clients with no\nresolvable email address (NoEmailCount).",
            "example": false
          },
          "recipientContactTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientContactType"
            },
            "description": "Client contact types for To recipients. Part of the optional To-recipient configuration.",
            "nullable": true
          },
          "recipientUserTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowStepAssignmentType"
            },
            "description": "User types for To recipients. Part of the optional To-recipient configuration.",
            "nullable": true
          },
          "additionalEmailAddresses": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Static email addresses included as To recipients on every email.\nPart of the optional To-recipient configuration.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "The client-selection part of an email broadcast, used to summarise the audience\nbefore a draft exists. Same selection semantics as create: a saved view or an\ninline filter (mutually exclusive), plus hand-picked additions and exclusions.\nOptionally include the To-recipient configuration to also count clients with\nno resolvable email address."
      },
      "EmailBroadcastAudienceSummaryDto": {
        "type": "object",
        "properties": {
          "clientCount": {
            "type": "integer",
            "description": "Total number of clients the selection resolves to (filter matches plus\nhand-picked additions, minus exclusions).",
            "format": "int32",
            "example": 142
          },
          "notEmailableCount": {
            "type": "integer",
            "description": "How many of those clients have an email contact preference that is not set —\nthey are skipped at send time unless the broadcast opts to include them.",
            "format": "int32",
            "example": 7
          },
          "noEmailCount": {
            "type": "integer",
            "description": "How many of the clients have no resolvable email address for the requested\nTo-recipient configuration — they are always skipped at send time.\nNull when the request did not include a To-recipient configuration.",
            "format": "int32",
            "nullable": true,
            "example": 3
          }
        },
        "additionalProperties": false,
        "description": "Summary counts for an email broadcast audience: how many clients the selection\nresolves to, and how many of those have not opted in to email contact."
      },
      "EmailBroadcastDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique code identifying this broadcast",
            "nullable": true,
            "example": "a1b2c3d4e5f64a7b8c9d0e1f2a3b4c5d"
          },
          "status": {
            "$ref": "#/components/schemas/EmailBroadcastStatus"
          },
          "contentBlockCode": {
            "type": "string",
            "description": "Content block code (category: Email) used as the email template.\nMutually exclusive with SubjectLine/BodyHtml.",
            "nullable": true,
            "example": "client-newsletter"
          },
          "subjectLine": {
            "type": "string",
            "description": "Inline email subject line with Liquid template syntax.\nMutually exclusive with ContentBlockCode.",
            "nullable": true,
            "example": "An update for {{ Client.Name }}"
          },
          "bodyHtml": {
            "type": "string",
            "description": "Inline email body HTML with Liquid template syntax.\nMutually exclusive with ContentBlockCode.",
            "nullable": true
          },
          "allContacts": {
            "type": "boolean",
            "description": "When true, every contact of each client with an email address receives the email\nas a To recipient, regardless of contact type. RecipientContactTypes is ignored.",
            "example": false
          },
          "recipientContactTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientContactType"
            },
            "description": "Client contact types for To recipients, resolved per client at send time.\nIgnored when AllContacts is true.",
            "nullable": true
          },
          "recipientUserTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowStepAssignmentType"
            },
            "description": "User types for To recipients (ClientManager, ClientPartner, ClientAssociate, ClientServiceManager),\nresolved per client at send time.",
            "nullable": true
          },
          "additionalEmailAddresses": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Static email addresses included as To recipients on every email.",
            "nullable": true
          },
          "ccContactTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientContactType"
            },
            "description": "Client contact types for CC recipients.",
            "nullable": true
          },
          "ccUserTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowStepAssignmentType"
            },
            "description": "User types for CC recipients.",
            "nullable": true
          },
          "ccEmailAddresses": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Static email addresses included as CC recipients on every email.",
            "nullable": true
          },
          "bccContactTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientContactType"
            },
            "description": "Client contact types for BCC recipients.",
            "nullable": true
          },
          "bccUserTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowStepAssignmentType"
            },
            "description": "User types for BCC recipients.",
            "nullable": true
          },
          "bccEmailAddresses": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Static email addresses included as BCC recipients on every email.",
            "nullable": true
          },
          "savedView": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "filter": {
            "$ref": "#/components/schemas/EmailBroadcastFilterDto"
          },
          "excludedClientCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Client codes excluded from the filter results.",
            "nullable": true
          },
          "additionalClientCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Hand-picked client codes added on top of the filter results.",
            "nullable": true
          },
          "onlyEmailableClients": {
            "type": "boolean",
            "description": "When true, clients whose email contact preference is not set are skipped.",
            "example": true
          },
          "addHeaderFooter": {
            "type": "boolean",
            "description": "When true, the tenant's email header and footer content blocks are wrapped\naround the body when the email is rendered.",
            "example": true
          },
          "configCode": {
            "type": "string",
            "description": "The email configuration (mailbox) code to send from.\nNull uses the tenant's default mailbox resolution.",
            "nullable": true,
            "example": "billing-mailbox"
          },
          "totalClients": {
            "type": "integer",
            "description": "Total number of sendable recipients, set when the broadcast is sent.",
            "format": "int32",
            "example": 142
          },
          "processedClients": {
            "type": "integer",
            "description": "Number of recipients processed so far (sent + failed).\nCompare with TotalClients to calculate progress.",
            "format": "int32",
            "example": 75
          },
          "failedClients": {
            "type": "integer",
            "description": "Number of recipients that failed so far.",
            "format": "int32",
            "example": 2
          },
          "startedDate": {
            "type": "string",
            "description": "When the broadcast started sending (UTC). Null until processing starts.",
            "format": "date-time",
            "nullable": true
          },
          "completedDate": {
            "type": "string",
            "description": "When the broadcast finished processing (UTC). Set for completion, failure and cancellation.",
            "format": "date-time",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "When the broadcast was created (UTC).",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "An email broadcast: an ad-hoc mass email to a filtered set of clients with per-client\nLiquid token rendering. Returned by the email broadcast endpoints."
      },
      "EmailBroadcastDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmailBroadcastDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "EmailBroadcastFilterDto": {
        "type": "object",
        "properties": {
          "managerCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter clients by their assigned manager's code(s).",
            "nullable": true
          },
          "partnerCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter clients by their assigned partner's code(s).",
            "nullable": true
          },
          "associateCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter clients by their assigned associate's code(s).",
            "nullable": true
          },
          "statuses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientStatus"
            },
            "description": "Filter clients by status(es).\nValues: Active, Inactive, Prospect, LostProspect",
            "nullable": true
          },
          "types": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientType"
            },
            "description": "Filter clients by their organization type(s).",
            "nullable": true
          },
          "serviceCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter clients by billable service code(s) they have assigned.",
            "nullable": true
          },
          "packageCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter clients by service package code(s) they have assigned.",
            "nullable": true
          },
          "teamCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter clients by their assigned team's code(s).",
            "nullable": true
          },
          "serviceStageCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter clients by service stage composite codes (format: \"serviceCode:stageCode\").",
            "nullable": true
          },
          "search": {
            "type": "string",
            "description": "Search across client code, name and internal reference.\nMinimum 3 characters.",
            "nullable": true,
            "example": "acme"
          }
        },
        "additionalProperties": false,
        "description": "Filter criteria for selecting which clients receive an email broadcast.\nSame wire shape as the CSV export filter — matches the filters on the client list endpoint.\nIf the filter is omitted entirely, only AdditionalClientCodes are included (pure hand-picked list).\nAn empty filter object selects all clients."
      },
      "EmailBroadcastPreviewDto": {
        "type": "object",
        "properties": {
          "subject": {
            "type": "string",
            "description": "Rendered subject line with Liquid tokens resolved for the sample client.",
            "nullable": true
          },
          "bodyHtml": {
            "type": "string",
            "description": "Rendered body HTML with header/footer/theme applied and Liquid tokens resolved for the sample client.",
            "nullable": true
          },
          "toRecipients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmailPreviewRecipientDto"
            },
            "description": "Resolved To recipients for the sample client.",
            "nullable": true
          },
          "ccRecipients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmailPreviewRecipientDto"
            },
            "description": "Resolved CC recipients for the sample client.",
            "nullable": true
          },
          "bccRecipients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmailPreviewRecipientDto"
            },
            "description": "Resolved BCC recipients for the sample client.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Preview of a broadcast email rendered for a specific sample client, with resolved recipients.\nReturned before sending so the user can review what will be sent."
      },
      "EmailBroadcastRecipientDto": {
        "type": "object",
        "properties": {
          "clientCode": {
            "type": "string",
            "description": "The client's code",
            "nullable": true,
            "example": "acme-ltd"
          },
          "clientName": {
            "type": "string",
            "description": "The client's name",
            "nullable": true,
            "example": "ACME Ltd"
          },
          "toRecipients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmailPreviewRecipientDto"
            },
            "description": "Resolved To recipients for this client's email.",
            "nullable": true
          },
          "ccRecipients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmailPreviewRecipientDto"
            },
            "description": "Resolved CC recipients for this client's email.",
            "nullable": true
          },
          "bccRecipients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmailPreviewRecipientDto"
            },
            "description": "Resolved BCC recipients for this client's email.",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/EmailBroadcastRecipientStatus"
          },
          "skipOrFailReason": {
            "type": "string",
            "description": "Why this client was skipped or the send failed. Null when Pending or Sent.",
            "nullable": true,
            "example": "No resolvable To recipients for this client"
          },
          "sentDate": {
            "type": "string",
            "description": "When the email was sent (UTC). Null unless Status is Sent.",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A single client within an email broadcast with its resolved recipients and delivery status.\nBefore send this is a live pre-send resolution; after send it reflects the stored snapshot."
      },
      "EmailBroadcastRecipientDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmailBroadcastRecipientDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "EmailBroadcastRecipientSortField": {
        "enum": [
          "Default"
        ],
        "type": "string"
      },
      "EmailBroadcastRecipientStatus": {
        "enum": [
          "Pending",
          "Sent",
          "Failed",
          "Skipped"
        ],
        "type": "string"
      },
      "EmailBroadcastSortField": {
        "enum": [
          "CreatedDate",
          "Status"
        ],
        "type": "string"
      },
      "EmailBroadcastStatus": {
        "enum": [
          "Draft",
          "Queued",
          "Sending",
          "Completed",
          "Failed",
          "Cancelled"
        ],
        "type": "string"
      },
      "EmailConfigDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique code identifying this email configuration",
            "nullable": true
          },
          "tenantUser": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "fromEmail": {
            "type": "string",
            "description": "The sender email address for this configuration",
            "nullable": true
          },
          "fromName": {
            "type": "string",
            "description": "The sender display name for this configuration",
            "nullable": true
          },
          "isDefault": {
            "type": "boolean",
            "description": "Whether this is the tenant's default email configuration"
          },
          "isSendShared": {
            "type": "boolean",
            "description": "Whether all users in the tenant can send emails from this configuration"
          },
          "isReadShared": {
            "type": "boolean",
            "description": "Whether all users in the tenant can read the emails received in this mailbox"
          },
          "sendEnabled": {
            "type": "boolean",
            "description": "Whether this configuration can send emails (true for SMTP, controlled by OAuth settings for OAuth providers)"
          },
          "readEnabled": {
            "type": "boolean",
            "description": "Whether this configuration can read/sync mailbox emails (only applicable for OAuth providers)"
          },
          "signature": {
            "type": "string",
            "description": "HTML signature to append to outbound emails sent from this configuration",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/ConfigurationStatus"
          },
          "statusReason": {
            "type": "string",
            "description": "User-facing explanation when the configuration is in an error state (e.g. ConnectionError);\nnull when the configuration is healthy. Surface this to the user alongside a reconnect prompt.",
            "nullable": true
          },
          "providerType": {
            "$ref": "#/components/schemas/ProviderType"
          },
          "smtpSettings": {
            "$ref": "#/components/schemas/SmtpSettingsResponseDto"
          },
          "oAuthStatus": {
            "$ref": "#/components/schemas/OAuthStatusResponse"
          },
          "createdDate": {
            "type": "string",
            "description": "Date this configuration was created",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "description": "Date this configuration was last updated",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response DTO for an email configuration"
      },
      "EmailConfigDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmailConfigDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "EmailConfigSortField": {
        "enum": [
          "FromEmail",
          "CreatedDate"
        ],
        "type": "string"
      },
      "EmailExecutionStateDto": {
        "type": "object",
        "properties": {
          "emailMessageId": {
            "type": "string",
            "description": "The GUID returned by the email service when the email was queued.\nUsed to query delivery status via the email history endpoints.",
            "format": "uuid"
          },
          "sentAt": {
            "type": "string",
            "description": "UTC timestamp of when the email was queued for sending.",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "Execution state for a SendEmail workflow step.\nContains information about the sent email after execution.\nRead-only - written by the system during step execution, never edited by users."
      },
      "EmailImportance": {
        "enum": [
          "Low",
          "Normal",
          "High"
        ],
        "type": "string",
        "description": "Email importance/priority level"
      },
      "EmailPreviewRecipientDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Display name of the recipient, if available.",
            "nullable": true
          },
          "email": {
            "type": "string",
            "description": "Email address of the recipient.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A resolved email recipient for preview display."
      },
      "EmailRecipient": {
        "required": [
          "email"
        ],
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "nullable": true
          },
          "email": {
            "maxLength": 256,
            "minLength": 1,
            "type": "string",
            "format": "email"
          }
        },
        "additionalProperties": false
      },
      "EmailRecipientConfig": {
        "type": "object",
        "properties": {
          "contactTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientContactType"
            },
            "description": "Client contact types to include (e.g. Main, Billing, Payroll)",
            "nullable": true
          },
          "userTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowStepAssignmentType"
            },
            "description": "User role types to include (e.g. ClientManager, ClientPartner).\nTaskOwner is not applicable outside workflow steps.",
            "nullable": true
          },
          "emailAddresses": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Static email addresses to include",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Configuration for resolving email recipients from client contacts, user roles, and static addresses.\nUsed by PCL settings, workflow steps, and any feature that needs configurable email recipients."
      },
      "EmailRecipientDto": {
        "required": [
          "email"
        ],
        "type": "object",
        "properties": {
          "email": {
            "minLength": 1,
            "type": "string",
            "description": "Email address",
            "format": "email"
          },
          "name": {
            "type": "string",
            "description": "Display name",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Email recipient DTO"
      },
      "EmailSettingsDto": {
        "type": "object",
        "properties": {
          "emailHeaderContentBlock": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "emailFooterContentBlock": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "designTheme": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "replyToEmail": {
            "type": "string",
            "description": "Reply-to email address for system emails",
            "nullable": true
          },
          "replyToName": {
            "type": "string",
            "description": "Reply-to display name for system emails",
            "nullable": true
          },
          "useClientManagerEmailMatching": {
            "type": "boolean",
            "description": "When enabled, outbound emails use the connection matching the client's manager email address instead of the default"
          }
        },
        "additionalProperties": false,
        "description": "Tenant-level configuration for outbound email branding and sender information.\nControls the visual appearance and sender details for system-generated emails\nsuch as proposal notifications, task assignments, and client communications."
      },
      "EmailSortField": {
        "enum": [
          "CreatedDate",
          "Subject",
          "Status"
        ],
        "type": "string",
        "description": "Specifies the field to sort emails by in list queries"
      },
      "EmailStatus": {
        "enum": [
          "Queued",
          "Processing",
          "Sent",
          "Failed",
          "Cancelled"
        ],
        "type": "string",
        "description": "Represents the status of an email message"
      },
      "EmailStepConfigDto": {
        "type": "object",
        "properties": {
          "contentBlockCode": {
            "maxLength": 50,
            "type": "string",
            "description": "Content block code for the email template.\nMust reference an existing Email category content block that defines the subject and body using Liquid syntax.\nMutually exclusive with SubjectLine/BodyHtml — provide one or the other.",
            "nullable": true
          },
          "subjectLine": {
            "maxLength": 500,
            "type": "string",
            "description": "Inline email subject line with Liquid template syntax.\nUse instead of ContentBlockCode for simple emails that don't need a reusable content block.\nMust be provided together with BodyHtml. Mutually exclusive with ContentBlockCode.",
            "nullable": true
          },
          "bodyHtml": {
            "type": "string",
            "description": "Inline email body HTML with Liquid template syntax.\nUse instead of ContentBlockCode for simple emails that don't need a reusable content block.\nMust be provided together with SubjectLine. Mutually exclusive with ContentBlockCode.",
            "nullable": true
          },
          "recipientContactTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientContactType"
            },
            "description": "Client contact types for To recipients.\nResolved from the task's client contacts at execution time.",
            "nullable": true
          },
          "recipientUserTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowStepAssignmentType"
            },
            "description": "User types for To recipients.\nResolved from client team assignments or task ownership at execution time.\nNote: SpecificUser is not applicable for email recipients.",
            "nullable": true
          },
          "additionalEmailAddresses": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Static email addresses for To recipients.\nUse for external recipients or email addresses not in the system.",
            "nullable": true
          },
          "ccContactTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientContactType"
            },
            "description": "Client contact types for CC recipients.",
            "nullable": true
          },
          "ccUserTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowStepAssignmentType"
            },
            "description": "User types for CC recipients.\nNote: SpecificUser is not applicable for email recipients.",
            "nullable": true
          },
          "ccEmailAddresses": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Static email addresses for CC recipients.",
            "nullable": true
          },
          "bccContactTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientContactType"
            },
            "description": "Client contact types for BCC recipients.",
            "nullable": true
          },
          "bccUserTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowStepAssignmentType"
            },
            "description": "User types for BCC recipients.\nNote: SpecificUser is not applicable for email recipients.",
            "nullable": true
          },
          "bccEmailAddresses": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Static email addresses for BCC recipients.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Configuration for SendEmail workflow steps.\nUsed for both workflow template definition and task workflow step instance customization.\nAll properties must be provided when creating or updating."
      },
      "EmailSummaryDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique message identifier",
            "format": "uuid"
          },
          "tenantCode": {
            "type": "string",
            "description": "Tenant code the email belongs to",
            "nullable": true
          },
          "subject": {
            "type": "string",
            "description": "Email subject line",
            "nullable": true
          },
          "recipientEmail": {
            "type": "string",
            "description": "Primary recipient email address (first To recipient)",
            "nullable": true
          },
          "recipientName": {
            "type": "string",
            "description": "Primary recipient display name (first To recipient)",
            "nullable": true
          },
          "fromEmail": {
            "type": "string",
            "description": "Sender email address",
            "nullable": true
          },
          "fromName": {
            "type": "string",
            "description": "Sender display name",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/EmailStatus"
          },
          "lastError": {
            "type": "string",
            "description": "Last error message if the email failed",
            "nullable": true
          },
          "metadata": {
            "type": "string",
            "description": "JSON metadata associated with the email",
            "nullable": true
          },
          "externalReference": {
            "type": "string",
            "description": "External reference from the calling application",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "When the email was created",
            "format": "date-time"
          },
          "sentAt": {
            "type": "string",
            "description": "When the email was sent (null if not yet sent)",
            "format": "date-time",
            "nullable": true
          },
          "retryCount": {
            "type": "integer",
            "description": "Number of retry attempts made",
            "format": "int32"
          },
          "maxRetryCount": {
            "type": "integer",
            "description": "Maximum number of retry attempts allowed",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Lightweight email summary for list responses"
      },
      "EngagementAcceptanceDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Engagement code",
            "nullable": true
          },
          "type": {
            "$ref": "#/components/schemas/EngagementType"
          },
          "numberOfServices": {
            "type": "integer",
            "description": "Number of services included in this engagement",
            "format": "int32"
          },
          "totalValue": {
            "type": "number",
            "description": "Total value of all services in this engagement (annualised recurring + one-off fees)",
            "format": "double"
          },
          "monthlyTotal": {
            "type": "number",
            "description": "Sum of monthly service prices (per-month amount, not annualised)",
            "format": "double"
          },
          "quarterlyTotal": {
            "type": "number",
            "description": "Sum of quarterly service prices (per-quarter amount)",
            "format": "double"
          },
          "annualTotal": {
            "type": "number",
            "description": "Sum of annual service prices",
            "format": "double"
          },
          "oneOffTotal": {
            "type": "number",
            "description": "Sum of one-off service prices",
            "format": "double"
          },
          "tenant": {
            "$ref": "#/components/schemas/TenantInfoDto"
          },
          "introContentHtml": {
            "type": "string",
            "description": "Intro content block HTML (if configured in EngagementSettings)",
            "nullable": true
          },
          "thankYouContentHtml": {
            "type": "string",
            "description": "Thank you content block HTML (if configured in EngagementSettings)",
            "nullable": true
          },
          "recipientFirstName": {
            "type": "string",
            "description": "Recipient first name",
            "nullable": true
          },
          "recipientLastName": {
            "type": "string",
            "description": "Recipient last name",
            "nullable": true
          },
          "recipientEmail": {
            "type": "string",
            "description": "Recipient email",
            "nullable": true
          },
          "showPracticeName": {
            "type": "boolean",
            "description": "Whether to show the practice name on the acceptance page"
          },
          "client": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "directDebitMandateUrl": {
            "type": "string",
            "description": "Direct debit mandate setup URL (if RequestDDMandate is enabled and tenant has DD connection)",
            "nullable": true
          },
          "amlOnboardingUrl": {
            "type": "string",
            "description": "AML onboarding URL for the main contact (if RequestAmlOnboarding is enabled and tenant has AML connection)",
            "nullable": true
          },
          "steps": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EngagementAcceptanceStepDto"
            },
            "description": "Server-computed acceptance flow steps with completion status",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response DTO for anonymous engagement acceptance page"
      },
      "EngagementAcceptanceStepDto": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string",
            "description": "Step identifier (e.g. \"proposal\", \"engagement\", \"directDebit\", \"aml\", \"complete\")",
            "nullable": true
          },
          "label": {
            "type": "string",
            "description": "Display label for the step header",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Short description shown under the label",
            "nullable": true
          },
          "isComplete": {
            "type": "boolean",
            "description": "Whether this step has been completed"
          },
          "actionUrl": {
            "type": "string",
            "description": "Action URL for this step (e.g. DD mandate URL, AML onboarding URL). Null if not applicable.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A step in the engagement acceptance flow, computed server-side."
      },
      "EngagementDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "nullable": true
          },
          "guid": {
            "type": "string",
            "description": "Unique identifier for this engagement",
            "format": "uuid"
          },
          "client": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "date": {
            "type": "string",
            "description": "Date of the engagement",
            "format": "date"
          },
          "status": {
            "$ref": "#/components/schemas/EngagementStatus"
          },
          "type": {
            "$ref": "#/components/schemas/EngagementType"
          },
          "typeName": {
            "type": "string",
            "description": "Display name for the engagement type (\"Proposal\" or \"Engagement Letter\")",
            "nullable": true,
            "readOnly": true
          },
          "recipientFirstName": {
            "type": "string",
            "description": "First name of the recipient for this engagement",
            "nullable": true
          },
          "recipientLastName": {
            "type": "string",
            "description": "Last name of the recipient for this engagement",
            "nullable": true
          },
          "recipientEmail": {
            "type": "string",
            "description": "Email address of the recipient for this engagement",
            "nullable": true
          },
          "requestDdMandate": {
            "type": "boolean",
            "description": "Per-proposal override for the \"set up Direct Debit\" acceptance step.\nNull means the practice default (from proposal settings) applies.",
            "nullable": true
          },
          "requestAmlOnboarding": {
            "type": "boolean",
            "description": "Per-proposal override for the identity-verification (AML) acceptance step.\nNull means the practice default (from proposal settings) applies.",
            "nullable": true
          },
          "hasProposalPdf": {
            "type": "boolean",
            "description": "Indicates whether a proposal PDF has been uploaded"
          },
          "hasLofEPdf": {
            "type": "boolean",
            "description": "Indicates whether a letter of engagement PDF has been uploaded"
          },
          "proposalTemplate": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "lofETemplate": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "acceptance": {
            "$ref": "#/components/schemas/AcceptanceDto"
          },
          "lastViewed": {
            "type": "string",
            "description": "Date and time when the engagement was last viewed",
            "format": "date-time",
            "nullable": true
          },
          "totalValue": {
            "type": "number",
            "description": "Total value of all services in this engagement (annualised recurring + one-off fees)",
            "format": "double"
          },
          "monthlyTotal": {
            "type": "number",
            "description": "Sum of monthly service prices (per-month amount, not annualised)",
            "format": "double"
          },
          "quarterlyTotal": {
            "type": "number",
            "description": "Sum of quarterly service prices (per-quarter amount)",
            "format": "double"
          },
          "annualTotal": {
            "type": "number",
            "description": "Sum of annual service prices",
            "format": "double"
          },
          "oneOffTotal": {
            "type": "number",
            "description": "Sum of one-off service prices",
            "format": "double"
          },
          "numberOfServices": {
            "type": "integer",
            "description": "Number of services included in this engagement",
            "format": "int32"
          },
          "proposalServices": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientBillableServiceDto"
            },
            "description": "List of services included in this engagement.\nThese are historical snapshots of ClientBillableServices at the time of engagement creation.\nThe original ClientBillableServices may have been modified or deleted since this engagement was created.",
            "nullable": true
          },
          "proposalPdfUrl": {
            "type": "string",
            "description": "Signed URL for streaming the proposal PDF without authentication.\nOnly populated when HasProposalPdf is true.",
            "nullable": true
          },
          "lofEPdfUrl": {
            "type": "string",
            "description": "Signed URL for streaming the letter of engagement PDF without authentication.\nOnly populated when HasLofEPdf is true.",
            "nullable": true
          },
          "link": {
            "type": "string",
            "description": "Public link for accepting this engagement.\nFormat: {WebApp.BaseUrl}/engagements/accept/{Guid}\nThis is a computed property and is not persisted in the database.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response DTO for engagement information"
      },
      "EngagementDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EngagementDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "EngagementEmailDto": {
        "type": "object",
        "properties": {
          "messageId": {
            "type": "string",
            "description": "The message ID from the email service",
            "format": "uuid"
          },
          "sentDate": {
            "type": "string",
            "description": "The date when the email was sent",
            "format": "date-time"
          },
          "subject": {
            "type": "string",
            "description": "The email subject line",
            "nullable": true
          },
          "toRecipients": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of recipient email addresses",
            "nullable": true
          },
          "status": {
            "type": "string",
            "description": "The status of the email (e.g., Sent, Delivered, Failed)",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Represents an email sent for an engagement"
      },
      "EngagementSettingsDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique identifier for the settings",
            "nullable": true
          },
          "introContentBlock": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "thankYouContentBlock": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "emailContentBlock": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "acceptanceTask": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "notifyClientManagerOnAcceptance": {
            "type": "boolean",
            "description": "Whether to send an email notification to the client manager when an engagement is accepted"
          },
          "notifyPartnerOnAcceptance": {
            "type": "boolean",
            "description": "Whether to send an email notification to the partner when an engagement is accepted"
          },
          "designTheme": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "showPracticeName": {
            "type": "boolean",
            "description": "Whether to display the practice name on engagement acceptance pages and documents"
          },
          "attachPDFs": {
            "type": "boolean",
            "description": "Whether to attach engagement PDFs to the engagement email"
          },
          "thankYouEmailContentBlock": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "requestDdMandate": {
            "type": "boolean",
            "description": "Whether to request a Direct Debit mandate when engagement is accepted"
          },
          "requestAmlOnboarding": {
            "type": "boolean",
            "description": "Whether to request AML onboarding for the main contact when engagement is accepted"
          },
          "amlOnboardingLevelId": {
            "type": "string",
            "description": "The AML platform onboarding level ID to use when creating the onboarding request",
            "nullable": true
          },
          "signaturePageContentBlock": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "useThirdPartyProposalPlatform": {
            "type": "boolean",
            "description": "Whether to use a third-party platform (e.g., Socket) for proposals instead of native Sodium proposals"
          },
          "addToPipelineOnSend": {
            "type": "boolean",
            "description": "Whether to add the client to a sales pipeline when their proposal is first sent"
          },
          "onSendPipeline": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          }
        },
        "additionalProperties": false,
        "description": "Tenant-level configuration for engagement behavior, branding, and notification settings.\nControls how engagements are presented to clients, what happens when they're accepted,\nand how engagement emails are formatted and delivered."
      },
      "EngagementSortField": {
        "enum": [
          "Client",
          "Code",
          "Date",
          "Status",
          "NumberOfServices",
          "TotalValue"
        ],
        "type": "string"
      },
      "EngagementStatus": {
        "enum": [
          "Unsent",
          "Sent",
          "Viewed",
          "Accepted",
          "Rejected"
        ],
        "type": "string"
      },
      "EngagementSummaryDto": {
        "type": "object",
        "properties": {
          "unsent": {
            "type": "integer",
            "description": "Count of engagements that have not been sent",
            "format": "int32"
          },
          "sent": {
            "type": "integer",
            "description": "Count of engagements that have been sent",
            "format": "int32"
          },
          "viewed": {
            "type": "integer",
            "description": "Count of engagements that have been viewed",
            "format": "int32"
          },
          "accepted": {
            "type": "integer",
            "description": "Count of engagements that have been accepted",
            "format": "int32"
          },
          "rejected": {
            "type": "integer",
            "description": "Count of engagements that have been rejected",
            "format": "int32"
          },
          "total": {
            "type": "integer",
            "description": "Total count of all engagements",
            "format": "int32",
            "readOnly": true
          },
          "unsentTotalValue": {
            "type": "number",
            "description": "Sum of total value for unsent engagements",
            "format": "double"
          },
          "sentTotalValue": {
            "type": "number",
            "description": "Sum of total value for sent engagements",
            "format": "double"
          },
          "viewedTotalValue": {
            "type": "number",
            "description": "Sum of total value for viewed engagements",
            "format": "double"
          },
          "acceptedTotalValue": {
            "type": "number",
            "description": "Sum of total value for accepted engagements",
            "format": "double"
          },
          "rejectedTotalValue": {
            "type": "number",
            "description": "Sum of total value for rejected engagements",
            "format": "double"
          },
          "overallTotalValue": {
            "type": "number",
            "description": "Total value across all engagements",
            "format": "double",
            "readOnly": true
          }
        },
        "additionalProperties": false,
        "description": "Summary of engagements grouped by status, including counts and total values"
      },
      "EngagementType": {
        "enum": [
          "ProposalAndEngagementLetter",
          "EngagementLetter"
        ],
        "type": "string"
      },
      "EnumMetadata": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "nullable": true
          },
          "value": {
            "type": "integer",
            "format": "int32"
          },
          "displayName": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "icon": {
            "type": "string",
            "nullable": true
          },
          "backgroundColor": {
            "type": "string",
            "nullable": true
          },
          "textColor": {
            "type": "string",
            "nullable": true
          },
          "group": {
            "type": "string",
            "nullable": true
          },
          "order": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "fontFamily": {
            "type": "string",
            "nullable": true
          },
          "fontFallback": {
            "type": "string",
            "nullable": true
          },
          "googleFontUrl": {
            "type": "string",
            "nullable": true
          },
          "isOnlineOnly": {
            "type": "boolean",
            "nullable": true
          },
          "hmrcService": {
            "type": "string",
            "nullable": true
          },
          "hmrcClientIdType": {
            "type": "string",
            "nullable": true
          },
          "hmrcClientIdSource": {
            "type": "string",
            "nullable": true
          },
          "hmrcKnownFactSource": {
            "type": "string",
            "nullable": true
          },
          "hmrcFlowType": {
            "type": "string",
            "nullable": true
          },
          "percentage": {
            "type": "number",
            "format": "double",
            "nullable": true
          },
          "isDataFormSupported": {
            "type": "boolean",
            "nullable": true
          },
          "dataFormDataType": {
            "type": "string",
            "nullable": true
          },
          "dataFormOptions": {
            "type": "string",
            "nullable": true
          },
          "hasOptions": {
            "type": "boolean",
            "nullable": true
          },
          "hasMaxLength": {
            "type": "boolean",
            "nullable": true
          },
          "hasLines": {
            "type": "boolean",
            "nullable": true
          },
          "hasDisplayWidth": {
            "type": "boolean",
            "nullable": true
          },
          "hasBooleanDisplayMode": {
            "type": "boolean",
            "nullable": true
          },
          "hasAllowedExtensions": {
            "type": "boolean",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "ExecuteWorkflowStepRequest": {
        "type": "object",
        "properties": {
          "documentCode": {
            "type": "string",
            "description": "The code of an existing client document to link to a DocumentApproval step.\nWhen provided, the document is linked to the step directly (must have ClientApprovalStatus of None or Pending).\nWhen omitted, the step must have a documentTemplateCode configured — the document will be generated asynchronously.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Optional request body for executing a workflow step.\nFor DocumentApproval steps: provide documentCode to link an existing document (manual upload or pre-generated from template).\nOmit documentCode to trigger async generation from the step's configured template.\nIgnored for other step types."
      },
      "ExternalDocumentDto": {
        "type": "object",
        "properties": {
          "externalFileId": {
            "type": "string",
            "description": "The platform-specific file identifier",
            "nullable": true
          },
          "fileName": {
            "type": "string",
            "description": "File name from the external platform",
            "nullable": true
          },
          "fileSize": {
            "type": "integer",
            "description": "File size in bytes",
            "format": "int64"
          },
          "modifiedDate": {
            "type": "string",
            "description": "Last modified date from the external platform",
            "format": "date-time",
            "nullable": true
          },
          "externalUrl": {
            "type": "string",
            "description": "URL to open/download the file from the provider",
            "nullable": true
          },
          "isFolder": {
            "type": "boolean",
            "description": "Whether this file is tracked in our system. When false, the fields below\n(Code, Title, Category, ReviewStatus, etc.) will be null."
          },
          "isTracked": {
            "type": "boolean"
          },
          "code": {
            "type": "string",
            "description": "Our internal document code (null for untracked files)",
            "nullable": true
          },
          "title": {
            "type": "string",
            "description": "Document title (null for untracked files)",
            "nullable": true
          },
          "summary": {
            "type": "string",
            "description": "Document summary (null for untracked files)",
            "nullable": true
          },
          "date": {
            "type": "string",
            "description": "Document date (null for untracked files)",
            "format": "date",
            "nullable": true
          },
          "category": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "reviewStatus": {
            "$ref": "#/components/schemas/ReviewStatus"
          },
          "clientApprovalStatus": {
            "$ref": "#/components/schemas/ClientApprovalStatus"
          },
          "visibleInClientPortal": {
            "type": "boolean",
            "description": "Whether this document is visible in the client portal (null for untracked files)",
            "nullable": true
          },
          "uploadedByContact": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "downloadUrl": {
            "type": "string",
            "description": "Signed download URL via our streaming endpoint (null for untracked files)",
            "nullable": true
          },
          "documentRequest": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "createdDate": {
            "type": "string",
            "description": "When the document was created in our system (null for untracked files)",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A file from the external storage provider, enriched with metadata from our DB\nwhen the file is tracked. Untracked files (uploaded outside Sodium) have null\nfor DB-sourced fields like Code, Category, ReviewStatus, etc."
      },
      "ExternalDocumentDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ExternalDocumentDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "ExternalFolderReferenceDto": {
        "type": "object",
        "properties": {
          "containerId": {
            "type": "string",
            "description": "Provider-specific identifier for the folder/container",
            "nullable": true
          },
          "driveId": {
            "type": "string",
            "description": "Provider-specific drive identifier (null when not applicable)",
            "nullable": true
          },
          "siteId": {
            "type": "string",
            "description": "Provider-specific site identifier (null when not applicable)",
            "nullable": true
          },
          "displayPath": {
            "type": "string",
            "description": "Human-readable path for display in the UI",
            "nullable": true
          },
          "externalUrl": {
            "type": "string",
            "description": "URL to open this folder in the provider's web UI",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "DTO for an external folder reference"
      },
      "ExternalMailboxEmailDetailResponse": {
        "type": "object",
        "properties": {
          "uniqueId": {
            "type": "string",
            "description": "Unique identifier for this email",
            "format": "uuid"
          },
          "direction": {
            "$ref": "#/components/schemas/MailboxEmailDirection"
          },
          "subject": {
            "type": "string",
            "description": "Email subject",
            "nullable": true
          },
          "fromEmail": {
            "type": "string",
            "description": "Sender email address",
            "nullable": true
          },
          "fromName": {
            "type": "string",
            "description": "Sender display name",
            "nullable": true
          },
          "htmlBody": {
            "type": "string",
            "description": "HTML body of the email",
            "nullable": true
          },
          "plainTextBody": {
            "type": "string",
            "description": "Plain text body of the email",
            "nullable": true
          },
          "messageDate": {
            "type": "string",
            "description": "When the email was received or sent",
            "format": "date-time"
          },
          "toRecipients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmailRecipientDto"
            },
            "description": "To recipients",
            "nullable": true
          },
          "ccRecipients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmailRecipientDto"
            },
            "description": "CC recipients",
            "nullable": true
          },
          "attachments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MailboxAttachmentDto"
            },
            "description": "Attachment metadata",
            "nullable": true
          },
          "conversationId": {
            "type": "string",
            "description": "Conversation ID for grouping messages into threads",
            "nullable": true
          },
          "reconnectRequired": {
            "type": "boolean",
            "description": "Whether the user needs to reconnect their mailbox to view this email"
          }
        },
        "additionalProperties": false,
        "description": "Full email detail response with body content fetched on-demand from the provider"
      },
      "ExternalMailboxEmailSummaryDto": {
        "type": "object",
        "properties": {
          "uniqueId": {
            "type": "string",
            "description": "Unique identifier for this email",
            "format": "uuid"
          },
          "subject": {
            "type": "string",
            "description": "Email subject",
            "nullable": true
          },
          "fromEmail": {
            "type": "string",
            "description": "Sender email address",
            "nullable": true
          },
          "fromName": {
            "type": "string",
            "description": "Sender display name",
            "nullable": true
          },
          "snippet": {
            "type": "string",
            "description": "Body preview snippet",
            "nullable": true
          },
          "messageDate": {
            "type": "string",
            "description": "When the email was received or sent",
            "format": "date-time"
          },
          "isRead": {
            "type": "boolean",
            "description": "Whether the email has been read"
          },
          "hasAttachments": {
            "type": "boolean",
            "description": "Whether the email has attachments"
          },
          "importance": {
            "$ref": "#/components/schemas/EmailImportance"
          },
          "conversationId": {
            "type": "string",
            "description": "Conversation ID for grouping messages into threads",
            "nullable": true
          },
          "configCode": {
            "type": "string",
            "description": "Configuration code (GUID) identifying which mailbox this email belongs to",
            "nullable": true
          },
          "folders": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CodeAndNameDto"
            },
            "description": "Folders/labels this email currently belongs to. For Outlook this is exactly one entry;\nfor Gmail an email can belong to many labels. Each entry's `Code` is the folder's\nUniqueId and `Name` is the display path.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Summary DTO for a mailbox email (used in list views)"
      },
      "ExternalMailboxEmailSummaryDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ExternalMailboxEmailSummaryDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "ExternalMailboxFolderDto": {
        "type": "object",
        "properties": {
          "uniqueId": {
            "type": "string",
            "description": "Folder UniqueId (Guid) — stable identifier suitable for URL routing and filter params.",
            "format": "uuid"
          },
          "configCode": {
            "type": "string",
            "description": "Configuration UniqueId (Guid) the folder belongs to. Lets the UI group the response\nper-mailbox or filter to a single mailbox client-side.",
            "format": "uuid"
          },
          "name": {
            "type": "string",
            "description": "Display name of the folder/label (e.g. \"Inbox\", \"Clients/Acme\").",
            "nullable": true
          },
          "path": {
            "type": "string",
            "description": "Provider-canonical path. For Outlook this is the full folder path\n(e.g. \"Inbox/Sub\"); for Gmail this is the label name (e.g. \"Clients/Acme\")\nwhere forward slashes denote hierarchy.",
            "nullable": true
          },
          "systemFolderType": {
            "$ref": "#/components/schemas/SystemFolderType"
          },
          "parentFolderUniqueId": {
            "type": "string",
            "description": "UniqueId of the parent folder, or null for top-level folders. Used to render Outlook\nfolder hierarchies. Gmail labels do not use this — hierarchy is encoded in Path.",
            "format": "uuid",
            "nullable": true
          },
          "isSystem": {
            "type": "boolean",
            "description": "True if the folder is provider-system (Inbox, Sent, etc.) rather than user-created."
          },
          "totalCount": {
            "type": "integer",
            "description": "Total number of emails currently mapped to this folder (junction row count).",
            "format": "int32"
          },
          "unreadCount": {
            "type": "integer",
            "description": "Number of unread emails currently mapped to this folder.",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "One folder (Outlook) or label (Gmail) belonging to a mailbox configuration.\nReturned by the tenant-scoped folders endpoint so the UI can render a folder/label\ntree across every accessible read-enabled configuration."
      },
      "ExternalProposalDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "External platform ID",
            "nullable": true
          },
          "proposalNumber": {
            "type": "string",
            "description": "Human-readable reference number (e.g., P-001234)",
            "nullable": true
          },
          "title": {
            "type": "string",
            "description": "Optional title",
            "nullable": true
          },
          "status": {
            "type": "string",
            "description": "Current status on the external platform",
            "nullable": true
          },
          "price": {
            "type": "number",
            "description": "Total price",
            "format": "double"
          },
          "recurringPrice": {
            "type": "number",
            "description": "Recurring component of the price",
            "format": "double"
          },
          "oneOffPrice": {
            "type": "number",
            "description": "One-off component of the price",
            "format": "double"
          },
          "currency": {
            "type": "string",
            "description": "ISO 4217 currency code",
            "nullable": true
          },
          "plannedStart": {
            "type": "string",
            "description": "Planned start date",
            "format": "date",
            "nullable": true
          },
          "endDate": {
            "type": "string",
            "description": "End date",
            "format": "date",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "description": "When the proposal was created",
            "format": "date-time",
            "nullable": true
          },
          "clientName": {
            "type": "string",
            "description": "Primary client name on the external platform",
            "nullable": true
          },
          "clientId": {
            "type": "string",
            "description": "Primary client ID on the external platform",
            "nullable": true
          },
          "externalUrl": {
            "type": "string",
            "description": "URL to view/edit the proposal on the external platform",
            "nullable": true
          },
          "approvalLink": {
            "type": "string",
            "description": "URL for the client to approve the proposal",
            "nullable": true
          },
          "version": {
            "type": "integer",
            "description": "Version number",
            "format": "int32"
          },
          "contactName": {
            "type": "string",
            "description": "Primary contact name",
            "nullable": true
          },
          "contactEmail": {
            "type": "string",
            "description": "Primary contact email",
            "nullable": true
          },
          "lines": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ExternalProposalLineDto"
            },
            "description": "Line items on the proposal (populated on detail only)",
            "nullable": true
          },
          "importedClient": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "hasServicesAssigned": {
            "type": "boolean",
            "description": "Whether the imported client has services from this proposal assigned.\nTrue when at least one mapped service exists on the client."
          }
        },
        "additionalProperties": false,
        "description": "A proposal from an external platform (Socket, etc.)"
      },
      "ExternalProposalDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ExternalProposalDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "ExternalProposalLineDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "External platform line ID",
            "nullable": true
          },
          "serviceTemplateId": {
            "type": "string",
            "description": "Service template ID on the external platform (used for service mapping)",
            "nullable": true
          },
          "title": {
            "type": "string",
            "description": "Line item title / service name",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Line item description",
            "nullable": true
          },
          "isRecurring": {
            "type": "boolean",
            "description": "Whether this is a recurring charge"
          },
          "price": {
            "type": "number",
            "description": "Price for this line",
            "format": "double"
          },
          "billingMethod": {
            "type": "string",
            "description": "Billing method (e.g., \"fixed\", \"hourly\")",
            "nullable": true
          },
          "mappedService": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "isAssignedToClient": {
            "type": "boolean",
            "description": "Whether this mapped service has already been assigned to the client"
          },
          "clientServiceStatus": {
            "$ref": "#/components/schemas/ServiceStatus"
          }
        },
        "additionalProperties": false,
        "description": "A line item on an external proposal"
      },
      "FieldDisplayWidth": {
        "enum": [
          "Small",
          "Medium",
          "Large",
          "Full"
        ],
        "type": "string"
      },
      "FilingHistoryAnnotation": {
        "type": "object",
        "properties": {
          "annotation": {
            "type": "string",
            "nullable": true
          },
          "date": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "FilingHistoryAssociatedFiling": {
        "type": "object",
        "properties": {
          "date": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "category": {
            "$ref": "#/components/schemas/FilingHistoryCategory"
          },
          "subcategory": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "type": {
            "type": "string",
            "nullable": true
          },
          "descriptionValues": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true
          },
          "actionDate": {
            "type": "string",
            "nullable": true
          },
          "formattedDescription": {
            "type": "string",
            "nullable": true,
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "FilingHistoryCategory": {
        "enum": [
          "Accounts",
          "Address",
          "AnnualReturn",
          "Capital",
          "ChangeOfName",
          "Incorporation",
          "Liquidation",
          "Miscellaneous",
          "Mortgage",
          "Officers",
          "Resolution",
          "PersonsWithSignificantControl"
        ],
        "type": "string"
      },
      "FilingHistoryDocument": {
        "type": "object",
        "properties": {
          "documentId": {
            "type": "string",
            "nullable": true
          },
          "documentType": {
            "type": "string",
            "nullable": true
          },
          "documentDescription": {
            "type": "string",
            "nullable": true
          },
          "documentDate": {
            "type": "string",
            "format": "date",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "FilingHistoryItem": {
        "type": "object",
        "properties": {
          "transactionId": {
            "type": "string",
            "nullable": true
          },
          "date": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "category": {
            "$ref": "#/components/schemas/FilingHistoryCategory"
          },
          "type": {
            "type": "string",
            "nullable": true
          },
          "subcategory": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "actionDate": {
            "type": "string",
            "nullable": true
          },
          "paperFiled": {
            "type": "string",
            "nullable": true
          },
          "barcode": {
            "type": "string",
            "nullable": true
          },
          "pages": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "documents": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FilingHistoryDocument"
            },
            "nullable": true
          },
          "descriptionValues": {
            "type": "object",
            "additionalProperties": {},
            "nullable": true
          },
          "annotations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FilingHistoryAnnotation"
            },
            "nullable": true
          },
          "resolutions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FilingHistoryResolution"
            },
            "nullable": true
          },
          "associatedFilings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FilingHistoryAssociatedFiling"
            },
            "nullable": true
          },
          "formattedDescription": {
            "type": "string",
            "nullable": true,
            "readOnly": true
          }
        },
        "additionalProperties": false
      },
      "FilingHistoryItemPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FilingHistoryItem"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "FilingHistoryResolution": {
        "type": "object",
        "properties": {
          "category": {
            "$ref": "#/components/schemas/FilingHistoryCategory"
          },
          "subcategory": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "documentId": {
            "type": "string",
            "nullable": true
          },
          "date": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "receiveDate": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "type": {
            "type": "string",
            "nullable": true
          },
          "deltaAt": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "FontSettingsDto": {
        "type": "object",
        "properties": {
          "fontFamily": {
            "$ref": "#/components/schemas/ThemeFont"
          },
          "fontSize": {
            "type": "number",
            "description": "Font size in points",
            "format": "float"
          },
          "color": {
            "type": "string",
            "description": "Text color in hex format (e.g., \"#000000\" for black)",
            "nullable": true
          },
          "bold": {
            "type": "boolean",
            "description": "Whether the text should be bold"
          },
          "italic": {
            "type": "boolean",
            "description": "Whether the text should be italic"
          },
          "underline": {
            "type": "boolean",
            "description": "Whether the text should be underlined"
          },
          "customFontFamily": {
            "maxLength": 200,
            "type": "string",
            "description": "Custom font family name (e.g., \"Garamond\"). Only used when FontFamily is set to Custom.",
            "nullable": true
          },
          "backgroundColor": {
            "type": "string",
            "description": "Optional background color in hex format (e.g., \"#f3f4f6\"). Used for table headers.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Typography settings for a specific text element (headings, body, tables, etc.) in a design theme.\nDefines font family, size, color, and text decorations."
      },
      "GenerateBillableServiceRequest": {
        "required": [
          "serviceName"
        ],
        "type": "object",
        "properties": {
          "serviceName": {
            "minLength": 1,
            "type": "string",
            "description": "The name of the service to generate"
          }
        },
        "additionalProperties": false,
        "description": "Request to generate a BillableService using AI"
      },
      "GenerateWorkflowRequest": {
        "required": [
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "minLength": 1,
            "type": "string",
            "description": "The name of the workflow to generate"
          },
          "description": {
            "type": "string",
            "description": "Optional description providing context for the workflow generation",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request to generate a Workflow using AI"
      },
      "GetMessageResponse": {
        "type": "object",
        "properties": {
          "messageId": {
            "type": "string",
            "description": "Unique message ID",
            "format": "uuid"
          },
          "status": {
            "$ref": "#/components/schemas/EmailStatus"
          },
          "createdDate": {
            "type": "string",
            "description": "When the message was created",
            "format": "date-time"
          },
          "processedAt": {
            "type": "string",
            "description": "When the message was processed",
            "format": "date-time",
            "nullable": true
          },
          "sentAt": {
            "type": "string",
            "description": "When the message was sent",
            "format": "date-time",
            "nullable": true
          },
          "retryCount": {
            "type": "integer",
            "description": "Number of retry attempts",
            "format": "int32"
          },
          "lastError": {
            "type": "string",
            "description": "Last error message if any",
            "nullable": true
          },
          "externalReference": {
            "type": "string",
            "description": "External reference from calling application",
            "nullable": true
          },
          "subject": {
            "type": "string",
            "description": "Email subject line",
            "nullable": true
          },
          "fromEmail": {
            "type": "string",
            "description": "Sender email address",
            "nullable": true
          },
          "fromName": {
            "type": "string",
            "description": "Sender display name",
            "nullable": true
          },
          "replyToEmail": {
            "type": "string",
            "description": "Reply-to email address",
            "nullable": true
          },
          "replyToName": {
            "type": "string",
            "description": "Reply-to display name",
            "nullable": true
          },
          "to": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmailRecipientDto"
            },
            "description": "List of To recipients",
            "nullable": true
          },
          "cc": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmailRecipientDto"
            },
            "description": "List of Cc recipients",
            "nullable": true
          },
          "bcc": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmailRecipientDto"
            },
            "description": "List of Bcc recipients",
            "nullable": true
          },
          "attachments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmailAttachmentInfoDto"
            },
            "description": "List of attachments (metadata only, not content)",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response for get message request containing full message details"
      },
      "HmrcBatchRequestError": {
        "type": "object",
        "properties": {
          "authorisationType": {
            "type": "string",
            "nullable": true
          },
          "error": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "HmrcBatchRequestResult": {
        "type": "object",
        "properties": {
          "succeeded": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          },
          "failed": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HmrcBatchRequestError"
            },
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "HmrcInvitationDetailsDto": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "description": "The raw HMRC invitation status (Pending, Accepted, Rejected, Cancelled, Expired, etc.)",
            "nullable": true
          },
          "clientActionUrl": {
            "type": "string",
            "description": "The URL the client clicks to approve the authorisation on Government Gateway.",
            "nullable": true
          },
          "dateRequested": {
            "type": "string",
            "description": "When the HMRC invitation was created.",
            "format": "date-time",
            "nullable": true
          },
          "expiresOn": {
            "type": "string",
            "description": "When the HMRC invitation expires.",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Details of an HMRC digital authorisation invitation"
      },
      "HolidayAdjustment": {
        "enum": [
          "None",
          "Skip",
          "MoveBefore",
          "MoveAfter"
        ],
        "type": "string"
      },
      "HttpValidationProblemDetails": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "nullable": true
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "detail": {
            "type": "string",
            "nullable": true
          },
          "instance": {
            "type": "string",
            "nullable": true
          },
          "errors": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "nullable": true
          }
        },
        "additionalProperties": {}
      },
      "IResult": {
        "type": "object",
        "additionalProperties": false
      },
      "ImageAssetDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique identifier (GUID)",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Name of the image asset",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Description of the image asset",
            "nullable": true
          },
          "originalFileName": {
            "type": "string",
            "description": "Original file name",
            "nullable": true
          },
          "contentType": {
            "type": "string",
            "description": "MIME type of the image",
            "nullable": true
          },
          "fileSize": {
            "type": "integer",
            "description": "File size in bytes",
            "format": "int64"
          },
          "widthPx": {
            "type": "integer",
            "description": "Image width in pixels (null for SVG)",
            "format": "int32",
            "nullable": true
          },
          "heightPx": {
            "type": "integer",
            "description": "Image height in pixels (null for SVG)",
            "format": "int32",
            "nullable": true
          },
          "sha256Hash": {
            "type": "string",
            "description": "SHA256 hash of the file",
            "nullable": true
          },
          "downloadUrl": {
            "type": "string",
            "description": "SAS URL for downloading the image (generated on-demand)",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "Date when the asset was created",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "description": "Date when the asset was last updated",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Data transfer object for image asset details"
      },
      "ImageAssetDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ImageAssetDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "ImageAssetSortField": {
        "enum": [
          "Name",
          "FileSize"
        ],
        "type": "string"
      },
      "ImportBillableServicesFromLibraryRequest": {
        "required": [
          "libraryCodes"
        ],
        "type": "object",
        "properties": {
          "libraryCodes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LibraryServiceImportItem"
            },
            "description": "The library services to import, each with a library code and optional overrides"
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for importing one or more billable services from the library"
      },
      "ImportFromLibraryRequest": {
        "type": "object",
        "properties": {
          "nameSuffix": {
            "type": "string",
            "description": "Suffix appended to the imported entity's Name on re-import (e.g. \"v2\", \"May 2026\").\nNull / empty means: server picks the next \"(N)\" if a row for this LibraryCode already\nexists in the tenant; no suffix on a first import.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request body for single-item library imports (Workflow, DocumentTemplate, DataForm).\nOptional — empty body / null fields are still accepted for first-time imports."
      },
      "ImportJobDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique code for this import job",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/ImportJobStatus"
          },
          "totalItems": {
            "type": "integer",
            "description": "Total number of items to be imported",
            "format": "int32",
            "nullable": true
          },
          "processedItems": {
            "type": "integer",
            "description": "Number of items processed so far",
            "format": "int32"
          },
          "successCount": {
            "type": "integer",
            "description": "Number of items successfully imported",
            "format": "int32"
          },
          "failureCount": {
            "type": "integer",
            "description": "Number of items that failed to import",
            "format": "int32"
          },
          "enrichFromCompaniesHouse": {
            "type": "boolean",
            "description": "Whether Companies House enrichment is enabled"
          },
          "startedDate": {
            "type": "string",
            "description": "When the job started processing",
            "format": "date-time",
            "nullable": true
          },
          "completedDate": {
            "type": "string",
            "description": "When the job completed",
            "format": "date-time",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "When the job was created",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "DTO representing an import job status"
      },
      "ImportJobStatus": {
        "enum": [
          "Queued",
          "InProgress",
          "Completed",
          "Failed",
          "Cancelled",
          "Draft"
        ],
        "type": "string"
      },
      "ImportPipelinesFromLibraryRequest": {
        "required": [
          "libraryCodes"
        ],
        "type": "object",
        "properties": {
          "libraryCodes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LibraryPipelineImportItem"
            },
            "description": "The library pipelines to import, each with a library code and optional overrides"
          }
        },
        "additionalProperties": false,
        "description": "Request to import one or more pipelines from the library"
      },
      "InitializeWorkflowStepsRequest": {
        "required": [
          "workflowCode"
        ],
        "type": "object",
        "properties": {
          "workflowCode": {
            "maxLength": 50,
            "minLength": 1,
            "type": "string",
            "description": "The workflow code to initialize steps for.\nMust be a valid workflow code that exists in the tenant.\n            \nWarning: This operation will:\n- Clear all existing workflow step progress for the task\n- Create new step instances based on the workflow template\n- Reset all progress counters to zero\n- Set initial assignments based on workflow step rules"
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for initializing or re-initializing workflow steps for a TaskItem.\nUsed when a workflow is first assigned to a task or when changing workflows.\n            \nAPI Usage:\n- POST /api/tenants/{tenant}/tasks/{taskCode}/workflow\n- Typically called automatically when a workflow is assigned to a task\n- Can be called manually to reset workflow progress\n            \nExample Usage:\n```\nPOST /api/tenants/acme/tasks/TASK-001/workflow\n{\n    \"workflowCode\": \"CLIENT-ONBOARDING\"\n}\n```"
      },
      "InitiateMandateSetupRequest": {
        "required": [
          "successRedirectUrl"
        ],
        "type": "object",
        "properties": {
          "successRedirectUrl": {
            "minLength": 1,
            "type": "string",
            "description": "The URL to redirect the user to after completing the mandate setup on GoCardless."
          }
        },
        "additionalProperties": false,
        "description": "Request model for initiating a GoCardless Direct Debit mandate setup."
      },
      "InvitationDetailsResponse": {
        "type": "object",
        "properties": {
          "tenantName": {
            "type": "string",
            "description": "The name of the tenant/practice",
            "nullable": true
          },
          "tenantCode": {
            "type": "string",
            "description": "The code of the tenant",
            "nullable": true
          },
          "userEmail": {
            "type": "string",
            "description": "The email address of the invited user",
            "nullable": true
          },
          "token": {
            "type": "string",
            "description": "The invitation token",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/TenantUserStatus"
          },
          "expiresOn": {
            "type": "string",
            "description": "When the invitation expires",
            "format": "date-time",
            "nullable": true
          },
          "acceptedAt": {
            "type": "string",
            "description": "When the invitation was accepted",
            "format": "date-time",
            "nullable": true
          },
          "declinedAt": {
            "type": "string",
            "description": "When the invitation was declined",
            "format": "date-time",
            "nullable": true
          },
          "isExpired": {
            "type": "boolean",
            "description": "Whether the invitation has expired"
          }
        },
        "additionalProperties": false,
        "description": "Response containing details about an invitation"
      },
      "InviteCodeDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique invite code string",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "When the invite code was created",
            "format": "date-time"
          },
          "isUsed": {
            "type": "boolean",
            "description": "Whether this invite code has been used to create a tenant"
          },
          "usedDate": {
            "type": "string",
            "description": "When the invite code was used (null if unused)",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Represents an invite code used to create new tenants in the system.\nInvite codes are generated by SuperAdmins and allocated to users who can then use them to register new organizations."
      },
      "InvoiceDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Platform-specific invoice identifier (unique within the accounting platform)",
            "nullable": true
          },
          "number": {
            "type": "string",
            "description": "Invoice number (as displayed in the accounting platform)",
            "nullable": true
          },
          "customerId": {
            "type": "string",
            "description": "Platform-specific customer identifier",
            "nullable": true
          },
          "customerName": {
            "type": "string",
            "description": "Customer/client name from the accounting platform",
            "nullable": true
          },
          "totalAmount": {
            "type": "number",
            "description": "Total invoice amount including tax",
            "format": "double"
          },
          "netAmount": {
            "type": "number",
            "description": "Net amount before tax",
            "format": "double"
          },
          "taxAmount": {
            "type": "number",
            "description": "Tax (VAT) amount",
            "format": "double"
          },
          "amountDue": {
            "type": "number",
            "description": "Outstanding amount still due (may be less than TotalAmount if partially paid)",
            "format": "double"
          },
          "date": {
            "type": "string",
            "description": "Invoice date (when the invoice was issued)",
            "format": "date-time"
          },
          "dueDate": {
            "type": "string",
            "description": "Payment due date (null if no due date specified)",
            "format": "date-time",
            "nullable": true
          },
          "status": {
            "type": "string",
            "description": "Invoice status (e.g., \"Draft\", \"Submitted\", \"Paid\", \"Overdue\")",
            "nullable": true
          },
          "currency": {
            "type": "string",
            "description": "Invoice currency code (e.g., \"GBP\", \"USD\", \"EUR\")",
            "nullable": true
          },
          "externalUrl": {
            "type": "string",
            "description": "Direct link to view the invoice in the accounting platform",
            "nullable": true
          },
          "isPdfAvailable": {
            "type": "boolean",
            "description": "Whether a PDF can be downloaded for this invoice via the /pdf endpoint"
          },
          "platformData": {
            "type": "object",
            "additionalProperties": {},
            "description": "Platform-specific data that doesn't fit into the common model",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Invoice data retrieved from third-party accounting platforms (Xero, QuickBooks, FreeAgent, etc.).\nUsed for displaying client invoice information and tracking outstanding balances within Sodium."
      },
      "InvoiceDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InvoiceDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "InvoiceLineItemResponse": {
        "required": [
          "applicationCode",
          "description"
        ],
        "type": "object",
        "properties": {
          "applicationCode": {
            "type": "string",
            "description": "The application that submitted this line item.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Description of the charge.",
            "nullable": true
          },
          "amount": {
            "type": "number",
            "description": "Net amount in pounds.",
            "format": "double"
          },
          "quantity": {
            "type": "integer",
            "description": "Quantity of items.",
            "format": "int32"
          },
          "vatRate": {
            "type": "number",
            "description": "VAT rate as a percentage (e.g., 20.00).",
            "format": "double"
          },
          "vatAmount": {
            "type": "number",
            "description": "VAT amount in pounds.",
            "format": "double"
          },
          "periodStart": {
            "type": "string",
            "description": "Start date of the billing period.",
            "format": "date",
            "nullable": true
          },
          "periodEnd": {
            "type": "string",
            "description": "End date of the billing period.",
            "format": "date",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response model representing a single line item on an invoice."
      },
      "InvoiceRecipient": {
        "required": [
          "email",
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "minLength": 1,
            "type": "string",
            "description": "The recipient's name."
          },
          "email": {
            "minLength": 1,
            "type": "string",
            "description": "The recipient's email address.",
            "format": "email"
          }
        },
        "additionalProperties": false,
        "description": "Represents an additional invoice recipient."
      },
      "InvoiceResponse": {
        "required": [
          "code",
          "companyName",
          "invoiceNumber",
          "vatNumber"
        ],
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code identifier for the invoice.",
            "nullable": true
          },
          "invoiceNumber": {
            "type": "string",
            "description": "The customer-facing invoice number (e.g., \"INV-000001\").",
            "nullable": true
          },
          "companyName": {
            "type": "string",
            "description": "The company name of the invoice issuer.",
            "nullable": true
          },
          "vatNumber": {
            "type": "string",
            "description": "The VAT registration number of the invoice issuer.",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/BillingInvoiceStatus"
          },
          "subtotalAmount": {
            "type": "number",
            "description": "The subtotal amount (sum of line items net amounts) before VAT, in pounds.",
            "format": "double"
          },
          "vatAmount": {
            "type": "number",
            "description": "The total VAT amount (sum of line item VAT amounts) in pounds.",
            "format": "double"
          },
          "totalAmount": {
            "type": "number",
            "description": "The total amount of the invoice (subtotal + VAT) in pounds.",
            "format": "double"
          },
          "dueDate": {
            "type": "string",
            "description": "The date when payment is due.",
            "format": "date",
            "nullable": true
          },
          "paidDate": {
            "type": "string",
            "description": "The date and time when payment was received.",
            "format": "date-time",
            "nullable": true
          },
          "failureReason": {
            "type": "string",
            "description": "The reason for payment failure, if applicable.",
            "nullable": true
          },
          "pdfBlobUrl": {
            "type": "string",
            "description": "Time-limited URL for downloading the invoice PDF. Null if PDF has not been generated.",
            "nullable": true
          },
          "lineItems": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InvoiceLineItemResponse"
            },
            "description": "The line items included in this invoice.",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "The date and time when the invoice was created.",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "Response model representing an invoice with its line items."
      },
      "InvoiceSubmissionResult": {
        "type": "object",
        "properties": {
          "submittedCount": {
            "type": "integer",
            "format": "int32"
          },
          "failedCount": {
            "type": "integer",
            "format": "int32"
          },
          "skippedCount": {
            "type": "integer",
            "format": "int32"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "InvoiceSummaryResponse": {
        "required": [
          "code",
          "invoiceNumber"
        ],
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code identifier for the invoice.",
            "nullable": true
          },
          "invoiceNumber": {
            "type": "string",
            "description": "The customer-facing invoice number.",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/BillingInvoiceStatus"
          },
          "totalAmount": {
            "type": "number",
            "description": "The total amount of the invoice (subtotal + VAT) in pounds.",
            "format": "double"
          },
          "dueDate": {
            "type": "string",
            "description": "The date when payment is due.",
            "format": "date",
            "nullable": true
          },
          "pdfBlobUrl": {
            "type": "string",
            "description": "Time-limited URL for downloading the invoice PDF. Null if PDF has not been generated.",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "The date and time when the invoice was created.",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "Summary response model for listing invoices (without line items)."
      },
      "InvoiceSummaryResponsePagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InvoiceSummaryResponse"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "KanbanStageCountDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The stage code",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The stage name",
            "nullable": true
          },
          "icon": {
            "type": "string",
            "description": "Stage icon (Lucide icon name)",
            "nullable": true
          },
          "color": {
            "type": "string",
            "description": "Stage colour (hex)",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "Display order of the stage on the board",
            "format": "int32"
          },
          "cardCount": {
            "type": "integer",
            "description": "Number of cards currently in this stage",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Per-stage card count for a kanban board, including the stage's display settings.\nOne row per stage on the board (stages with no cards are included with a count of 0).\nShared by service boards and sales pipeline boards."
      },
      "KanbanTaskDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The task code (for linking to the task page)",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The task name",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/TaskItemStatus"
          },
          "dueDate": {
            "type": "string",
            "description": "The task due date. Used by the frontend to determine if the task is overdue.",
            "format": "date-time",
            "nullable": true
          },
          "currentStepName": {
            "type": "string",
            "description": "The current workflow step name (if the task has an active workflow).\nWhen present, this is more useful than the task name on kanban cards.",
            "nullable": true
          },
          "currentStepStatus": {
            "$ref": "#/components/schemas/TaskItemStatus"
          }
        },
        "additionalProperties": false,
        "description": "Lightweight task summary for kanban board cards"
      },
      "LibraryPipelineImportItem": {
        "required": [
          "libraryCode"
        ],
        "type": "object",
        "properties": {
          "libraryCode": {
            "minLength": 1,
            "type": "string",
            "description": "The library code of the pipeline to import"
          },
          "name": {
            "type": "string",
            "description": "Optional: Override the name of the pipeline from the library template",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Optional: Override the description of the pipeline from the library template",
            "nullable": true
          },
          "defaultManagedByUserCode": {
            "type": "string",
            "description": "Optional: Code of the user who manages this pipeline's cards by default",
            "nullable": true
          },
          "nameSuffix": {
            "type": "string",
            "description": "Optional: Name suffix applied to the pipeline and every cascaded task/template on re-import\n(e.g. \"v2\"). When omitted and the pipeline was already imported, \"(N)\" is auto-generated.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A single library pipeline to import, with its code and optional overrides"
      },
      "LibraryServiceImportItem": {
        "required": [
          "libraryCode"
        ],
        "type": "object",
        "properties": {
          "libraryCode": {
            "minLength": 1,
            "type": "string",
            "description": "The library code of the service to import"
          },
          "name": {
            "type": "string",
            "description": "Optional: Override the name of the service from the library template",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Optional: Override the description of the service from the library template",
            "nullable": true
          },
          "isArchived": {
            "type": "boolean",
            "description": "Optional: Override whether this service is archived (defaults to false)",
            "nullable": true
          },
          "accountingCode": {
            "maxLength": 20,
            "minLength": 0,
            "type": "string",
            "description": "Optional: Set the accounting code for this service (max 20 characters)",
            "nullable": true
          },
          "defaultManagedByUserCode": {
            "type": "string",
            "description": "Optional: Set the code of the user who is the default manager for this service",
            "nullable": true
          },
          "serviceScheduleContentCode": {
            "type": "string",
            "description": "Optional: Override the content block code for service schedule from library",
            "nullable": true
          },
          "proposalContentCode": {
            "type": "string",
            "description": "Optional: Override the content block code for proposals from library",
            "nullable": true
          },
          "category": {
            "$ref": "#/components/schemas/ServiceCategory"
          },
          "pricing": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BillableServicePricingOptionDto"
            },
            "description": "Optional: Override the pricing options from the library template",
            "nullable": true
          },
          "pricingFactors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PricingFactorDto"
            },
            "description": "Optional: Override the pricing factors from the library template",
            "nullable": true
          },
          "nameSuffix": {
            "type": "string",
            "description": "Optional suffix appended to the service name and all related recurring and onboarding tasks names on re-import\n(e.g. \"v2\", \"May 2026\"). When omitted and the tenant already has a copy of this library\nservice, the next available \"(N)\" suffix will be used.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A single library service to import, with its code and optional overrides"
      },
      "LibraryStatus": {
        "enum": [
          "NotFromLibrary",
          "UpToDate",
          "LocallyModified",
          "LibraryUpdated"
        ],
        "type": "string",
        "description": "Describes a library-imported entity's relationship to its source library template."
      },
      "LinkConversationTaskRequest": {
        "required": [
          "taskItemCode"
        ],
        "type": "object",
        "properties": {
          "taskItemCode": {
            "minLength": 1,
            "type": "string",
            "description": "The code of the task to link"
          }
        },
        "additionalProperties": false,
        "description": "Request to link a task to a conversation"
      },
      "LinkType": {
        "enum": [
          "Other",
          "Website",
          "LinkedIn",
          "Instagram",
          "Facebook",
          "Twitter"
        ],
        "type": "string"
      },
      "LinkedWorkflowStepDto": {
        "type": "object",
        "properties": {
          "groupNumber": {
            "type": "integer",
            "description": "The group number of the step within the task's workflow",
            "format": "int32"
          },
          "stepNumber": {
            "type": "integer",
            "description": "The step number within the group",
            "format": "int32"
          },
          "name": {
            "type": "string",
            "description": "The name of the step",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A workflow step linked from a time entry or running timer. Steps have no public code —\nthey are identified within their task by group number and step number."
      },
      "ListEmailsResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmailSummaryDto"
            },
            "description": "List of email summaries for the current page",
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "description": "Total number of emails matching the filter criteria",
            "format": "int32"
          },
          "offset": {
            "type": "integer",
            "description": "Number of records skipped (pagination offset)",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "description": "Maximum number of records returned per page",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean",
            "description": "Indicates if there are more records available beyond this page"
          }
        },
        "additionalProperties": false,
        "description": "Paginated response for listing emails"
      },
      "MailboxAttachmentDto": {
        "type": "object",
        "properties": {
          "attachmentId": {
            "type": "string",
            "description": "Provider-specific attachment ID",
            "nullable": true
          },
          "fileName": {
            "type": "string",
            "description": "File name",
            "nullable": true
          },
          "contentType": {
            "type": "string",
            "description": "MIME content type",
            "nullable": true
          },
          "size": {
            "type": "integer",
            "description": "Size in bytes",
            "format": "int64"
          },
          "contentId": {
            "type": "string",
            "description": "Content ID for inline attachments (CID reference used in HTML body).\nNull for regular (non-inline) attachments.",
            "nullable": true
          },
          "isInline": {
            "type": "boolean",
            "description": "Whether this attachment is inline (embedded in the HTML body via CID reference)"
          }
        },
        "additionalProperties": false,
        "description": "Attachment metadata from the provider"
      },
      "MailboxConversationSortField": {
        "enum": [
          "LatestMessageDate",
          "Subject",
          "MessageCount"
        ],
        "type": "string",
        "description": "Specifies the field to sort mailbox conversations by in list queries"
      },
      "MailboxEmailDirection": {
        "enum": [
          "Inbound",
          "Outbound"
        ],
        "type": "string",
        "description": "Represents the direction of an email in the external mailbox"
      },
      "MailboxMessageSortField": {
        "enum": [
          "MessageDate",
          "Subject",
          "Sender"
        ],
        "type": "string",
        "description": "Specifies the field to sort mailbox messages by in list queries"
      },
      "MailboxThreadSummaryDto": {
        "type": "object",
        "properties": {
          "conversationId": {
            "type": "string",
            "description": "Conversation ID (used in URL routes and to fetch conversation messages)",
            "nullable": true
          },
          "subject": {
            "type": "string",
            "description": "Subject of the latest message in the thread",
            "nullable": true
          },
          "snippet": {
            "type": "string",
            "description": "Snippet/preview of the latest message in the thread",
            "nullable": true
          },
          "latestMessageDate": {
            "type": "string",
            "description": "Date of the latest message in the thread",
            "format": "date-time"
          },
          "latestFromEmail": {
            "type": "string",
            "description": "Sender email of the latest message",
            "nullable": true
          },
          "latestFromName": {
            "type": "string",
            "description": "Sender display name of the latest message",
            "nullable": true
          },
          "messageCount": {
            "type": "integer",
            "description": "Total number of messages in the thread",
            "format": "int32"
          },
          "unreadCount": {
            "type": "integer",
            "description": "Number of unread messages in the thread",
            "format": "int32"
          },
          "hasAttachments": {
            "type": "boolean",
            "description": "Whether any message in the thread has attachments"
          },
          "importance": {
            "$ref": "#/components/schemas/EmailImportance"
          },
          "latestMessageUniqueId": {
            "type": "string",
            "description": "UniqueId of the latest message (useful for navigating to it)",
            "format": "uuid"
          },
          "configCode": {
            "type": "string",
            "description": "Configuration code (GUID) identifying which mailbox this thread belongs to",
            "nullable": true
          },
          "folders": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CodeAndNameDto"
            },
            "description": "Folders/labels that any message in this thread currently belongs to. For Gmail this is\nthe union across all messages in the conversation; for Outlook usually one entry. Each\nentry's `Code` is the folder's UniqueId and `Name` is the display path.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Summary DTO for a mailbox conversation (one entry per conversation in list views)"
      },
      "MailboxThreadSummaryDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MailboxThreadSummaryDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "MailingListSubscriptionDto": {
        "required": [
          "email"
        ],
        "type": "object",
        "properties": {
          "email": {
            "minLength": 1,
            "type": "string",
            "format": "email"
          },
          "fullName": {
            "type": "string",
            "nullable": true
          },
          "practiceName": {
            "type": "string",
            "nullable": true
          },
          "redirectUrl": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "MandateDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "nullable": true
          },
          "reference": {
            "type": "string",
            "nullable": true
          },
          "payerId": {
            "type": "string",
            "nullable": true
          },
          "payerName": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string",
            "nullable": true
          },
          "scheme": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "authorizationUrl": {
            "type": "string",
            "nullable": true
          },
          "webUrl": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response DTO for a direct debit mandate"
      },
      "MandateSetupResponse": {
        "required": [
          "redirectUrl"
        ],
        "type": "object",
        "properties": {
          "redirectUrl": {
            "type": "string",
            "description": "The GoCardless URL to redirect the user to for mandate authorisation.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response model returned when initiating a GoCardless mandate setup.\nContains the URL to redirect the user to for authorisation."
      },
      "MandateSummaryResponse": {
        "required": [
          "status"
        ],
        "type": "object",
        "properties": {
          "status": {
            "$ref": "#/components/schemas/PaymentMandateStatus"
          },
          "scheme": {
            "type": "string",
            "description": "The Direct Debit scheme (e.g., \"bacs\", \"sepa_core\").",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "When the mandate was created.",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "Summary of the active or most recent payment mandate for a billing account."
      },
      "MapExternalClientRequest": {
        "required": [
          "clientCode",
          "externalClientId"
        ],
        "type": "object",
        "properties": {
          "externalClientId": {
            "minLength": 1,
            "type": "string",
            "description": "The external platform's client ID"
          },
          "clientCode": {
            "minLength": 1,
            "type": "string",
            "description": "The Sodium client code to map to"
          }
        },
        "additionalProperties": false,
        "description": "Request to manually map an external platform client to an existing Sodium client"
      },
      "MarginsDto": {
        "type": "object",
        "properties": {
          "top": {
            "type": "number",
            "description": "Top margin in millimeters (default: 25mm)",
            "format": "float"
          },
          "bottom": {
            "type": "number",
            "description": "Bottom margin in millimeters (default: 25mm)",
            "format": "float"
          },
          "left": {
            "type": "number",
            "description": "Left margin in millimeters (default: 20mm)",
            "format": "float"
          },
          "right": {
            "type": "number",
            "description": "Right margin in millimeters (default: 20mm)",
            "format": "float"
          }
        },
        "additionalProperties": false,
        "description": "Page margin configuration for generated documents.\nAll measurements are in millimeters."
      },
      "MaritalStatus": {
        "enum": [
          "Single",
          "Married",
          "CivilPartnership",
          "Divorced",
          "Widowed",
          "Separated"
        ],
        "type": "string"
      },
      "MaterialiseProjectedTaskRequest": {
        "type": "object",
        "properties": {
          "projectedTaskCode": {
            "type": "string",
            "description": "The composite code of the projected task to materialise\nFormat: proj-{recurringTaskCode}-{clientCode}-{yyyyMMdd}",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request to materialise a projected task into a saved task"
      },
      "MonthDayType": {
        "enum": [
          "First",
          "Second",
          "Third",
          "Fourth",
          "Last"
        ],
        "type": "string"
      },
      "MonthFlags": {
        "enum": [
          "None",
          "January",
          "February",
          "March",
          "April",
          "May",
          "June",
          "July",
          "SemiAnnual",
          "August",
          "September",
          "October",
          "Quarterly",
          "November",
          "December",
          "AllMonths"
        ],
        "type": "string"
      },
      "Nationality": {
        "enum": [
          "Afghan",
          "Albanian",
          "Algerian",
          "American",
          "Andorran",
          "Angolan",
          "Antiguan",
          "Argentine",
          "Armenian",
          "Australian",
          "Austrian",
          "Azerbaijani",
          "Bahamian",
          "Bahraini",
          "Bangladeshi",
          "Barbadian",
          "Belarusian",
          "Belgian",
          "Belizean",
          "Beninese",
          "Bhutanese",
          "Bolivian",
          "Bosnian",
          "Botswanan",
          "Brazilian",
          "British",
          "Bruneian",
          "Bulgarian",
          "Burkinabe",
          "Burmese",
          "Burundian",
          "Cambodian",
          "Cameroonian",
          "Canadian",
          "CapeVerdean",
          "CentralAfrican",
          "Chadian",
          "Chilean",
          "Chinese",
          "Colombian",
          "Comoran",
          "Congolese",
          "CostaRican",
          "Croatian",
          "Cuban",
          "Cypriot",
          "Czech",
          "Danish",
          "Djiboutian",
          "Dominican",
          "Dutch",
          "EastTimorese",
          "Ecuadorean",
          "Egyptian",
          "Emirati",
          "EquatorialGuinean",
          "Eritrean",
          "Estonian",
          "Eswatini",
          "Ethiopian",
          "Fijian",
          "Filipino",
          "Finnish",
          "French",
          "Gabonese",
          "Gambian",
          "Georgian",
          "German",
          "Ghanaian",
          "Greek",
          "Grenadian",
          "Guatemalan",
          "Guinean",
          "GuineaBissauan",
          "Guyanese",
          "Haitian",
          "Honduran",
          "Hungarian",
          "Icelandic",
          "Indian",
          "Indonesian",
          "Iranian",
          "Iraqi",
          "Irish",
          "Israeli",
          "Italian",
          "Ivorian",
          "Jamaican",
          "Japanese",
          "Jordanian",
          "Kazakh",
          "Kenyan",
          "Kiribati",
          "Kuwaiti",
          "Kyrgyz",
          "Laotian",
          "Latvian",
          "Lebanese",
          "Liberian",
          "Libyan",
          "Liechtenstein",
          "Lithuanian",
          "Luxembourgish",
          "Macedonian",
          "Malagasy",
          "Malawian",
          "Malaysian",
          "Maldivian",
          "Malian",
          "Maltese",
          "Marshallese",
          "Mauritanian",
          "Mauritian",
          "Mexican",
          "Micronesian",
          "Moldovan",
          "Monegasque",
          "Mongolian",
          "Montenegrin",
          "Moroccan",
          "Mosotho",
          "Mozambican",
          "Namibian",
          "Nauruan",
          "Nepalese",
          "NewZealander",
          "Nicaraguan",
          "Nigerian",
          "Nigerien",
          "NorthKorean",
          "Norwegian",
          "Omani",
          "Pakistani",
          "Palauan",
          "Palestinian",
          "Panamanian",
          "PapuaNewGuinean",
          "Paraguayan",
          "Peruvian",
          "Polish",
          "Portuguese",
          "Qatari",
          "Romanian",
          "Russian",
          "Rwandan",
          "SaintKittsAndNevis",
          "SaintLucian",
          "Salvadoran",
          "Samoan",
          "SanMarinese",
          "SaoTomean",
          "Saudi",
          "Senegalese",
          "Serbian",
          "Seychellois",
          "SierraLeonean",
          "Singaporean",
          "Slovak",
          "Slovenian",
          "SolomonIslander",
          "Somali",
          "SouthAfrican",
          "SouthKorean",
          "SouthSudanese",
          "Spanish",
          "SriLankan",
          "Sudanese",
          "Surinamese",
          "Swedish",
          "Swiss",
          "Syrian",
          "Taiwanese",
          "Tajik",
          "Tanzanian",
          "Thai",
          "Togolese",
          "Tongan",
          "Trinidadian",
          "Tunisian",
          "Turkish",
          "Turkmen",
          "Tuvaluan",
          "Ugandan",
          "Ukrainian",
          "Uruguayan",
          "Uzbek",
          "Vanuatuan",
          "Vatican",
          "Venezuelan",
          "Vietnamese",
          "Vincentian",
          "Yemeni",
          "Zambian",
          "Zimbabwean"
        ],
        "type": "string"
      },
      "NominalCode": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "type": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "NoteDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this note",
            "nullable": true
          },
          "text": {
            "type": "string",
            "description": "The note text",
            "nullable": true
          },
          "date": {
            "type": "string",
            "description": "The date/time of the note",
            "format": "date-time"
          },
          "noteFromUser": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "pinnedLevel": {
            "type": "integer",
            "description": "The pinned level for ordering pinned notes",
            "format": "int32"
          },
          "createdDate": {
            "type": "string",
            "description": "When the note was created",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "description": "When the note was last updated",
            "format": "date-time",
            "nullable": true
          },
          "stepNumber": {
            "type": "integer",
            "description": "The workflow step number if this is a step-level note (null for task-level notes)",
            "format": "int32",
            "nullable": true
          },
          "groupNumber": {
            "type": "integer",
            "description": "The workflow group number if this is a step-level note (null for task-level notes)",
            "format": "int32",
            "nullable": true
          },
          "stepName": {
            "type": "string",
            "description": "The name of the workflow step if this is a step-level note (null for task-level notes)",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A note attached to an entity such as a client or task"
      },
      "NoteDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NoteDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "OAuthSettingsRequest": {
        "required": [
          "returnUrl"
        ],
        "type": "object",
        "properties": {
          "returnUrl": {
            "minLength": 1,
            "type": "string",
            "description": "URL to redirect to after OAuth flow completes (success or failure)"
          },
          "allowSend": {
            "type": "boolean",
            "description": "Whether this configuration should be able to send emails (defaults to true)"
          },
          "allowRead": {
            "type": "boolean",
            "description": "Whether this configuration should be able to read/sync mailbox emails (defaults to false)"
          }
        },
        "additionalProperties": false,
        "description": "OAuth settings for initiating OAuth flow (used with Microsoft365 or Google provider types)"
      },
      "OAuthStatusResponse": {
        "type": "object",
        "properties": {
          "isConnected": {
            "type": "boolean",
            "description": "Whether OAuth is connected"
          },
          "sendAsEmail": {
            "type": "string",
            "description": "Email address being sent as (null if not connected)",
            "nullable": true
          },
          "connectedBy": {
            "type": "string",
            "description": "Email of the user who authorized (null if not connected)",
            "nullable": true
          },
          "connectedAt": {
            "type": "string",
            "description": "When OAuth was connected (null if not connected)",
            "format": "date-time",
            "nullable": true
          },
          "authorisationUrl": {
            "type": "string",
            "description": "Authorisation URL to redirect user to for OAuth flow (only present when initiating OAuth)",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response containing OAuth connection status for Microsoft365/Google providers"
      },
      "Officer": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "nullable": true
          },
          "officerRole": {
            "type": "string",
            "nullable": true
          },
          "appointedOn": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "resignedOn": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "nationality": {
            "type": "string",
            "nullable": true
          },
          "countryOfResidence": {
            "type": "string",
            "nullable": true
          },
          "dateOfBirth": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "address": {
            "$ref": "#/components/schemas/OfficerAddress"
          },
          "formerNames": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          },
          "occupation": {
            "type": "string",
            "nullable": true
          },
          "officerId": {
            "type": "string",
            "nullable": true
          },
          "appointmentsUrl": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "OfficerAddress": {
        "type": "object",
        "properties": {
          "addressLine1": {
            "type": "string",
            "nullable": true
          },
          "addressLine2": {
            "type": "string",
            "nullable": true
          },
          "locality": {
            "type": "string",
            "nullable": true
          },
          "premises": {
            "type": "string",
            "nullable": true
          },
          "postalCode": {
            "type": "string",
            "nullable": true
          },
          "country": {
            "type": "string",
            "nullable": true
          },
          "region": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "OnboardingTaskTemplateDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Stable identifier. For library-shipped items this is the library code; for tenant-imported\nitems this is the tenant entity's own code.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name shown to users in lists, dialogs, and the import browser.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Optional human-readable summary of what this entity is for.",
            "nullable": true
          },
          "libraryCode": {
            "type": "string",
            "description": "The Code of the library template this entity was imported from, or null if the entity\nis not from the library. Read-only — cannot be changed once set. Example: \"vat_returns\".",
            "nullable": true
          },
          "libraryStatus": {
            "$ref": "#/components/schemas/LibraryStatus"
          },
          "isImported": {
            "type": "boolean",
            "description": "True if the tenant has already imported this library item."
          },
          "deprecated": {
            "type": "boolean",
            "description": "True if this library item has been retired. Deprecated items are hidden from the import\nbrowser (so new tasks cannot be created from them) but remain available for revert-to-library\non existing imports."
          },
          "billableService": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "timeEstimateMinutes": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "dueDateOffsetDays": {
            "type": "integer",
            "description": "Days after service start date for the task due date",
            "format": "int32"
          },
          "assignmentType": {
            "$ref": "#/components/schemas/AssignmentType"
          },
          "assignedUser": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "assignedTeam": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "workflow": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "category": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "checklist": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChecklistItemDto"
            },
            "description": "Checklist items for this onboarding task template",
            "nullable": true
          },
          "active": {
            "type": "boolean",
            "description": "Whether this template is active"
          }
        },
        "additionalProperties": false,
        "description": "DTO for onboarding task templates, exposing only codes and enums (never DB IDs)."
      },
      "OnboardingTaskTemplateDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OnboardingTaskTemplateDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "OnboardingTaskTemplateSortField": {
        "enum": [
          "DueDateOffsetDays",
          "Name"
        ],
        "type": "string"
      },
      "OpenDocumentRequestRequest": {
        "type": "object",
        "properties": {
          "recipientEmails": {
            "type": "string",
            "description": "Comma-separated email addresses to send the document request to.\nAt least one is required.",
            "nullable": true
          },
          "chaseFrequencyDays": {
            "type": "integer",
            "description": "Override for the chase frequency in days. If not specified, the tenant default is used.",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for opening (sending to client) a document request.\nRequires at least one recipient email address."
      },
      "OpenRouterChoice": {
        "type": "object",
        "properties": {
          "message": {
            "$ref": "#/components/schemas/OpenRouterMessage"
          }
        },
        "additionalProperties": false,
        "description": "A completion choice from the AI model"
      },
      "OpenRouterError": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string",
            "description": "The error message",
            "nullable": true
          },
          "type": {
            "type": "string",
            "description": "The error type",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Error information from OpenRouter"
      },
      "OpenRouterMessage": {
        "type": "object",
        "properties": {
          "content": {
            "type": "string",
            "description": "The generated text content",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Message content from the AI model"
      },
      "OpenRouterResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The response ID from OpenRouter",
            "nullable": true
          },
          "choices": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OpenRouterChoice"
            },
            "description": "List of completion choices returned by the AI model",
            "nullable": true
          },
          "usage": {
            "$ref": "#/components/schemas/OpenRouterUsage"
          },
          "error": {
            "$ref": "#/components/schemas/OpenRouterError"
          }
        },
        "additionalProperties": false,
        "description": "Response from OpenRouter API for AI generation requests"
      },
      "OpenRouterUsage": {
        "type": "object",
        "properties": {
          "prompt_tokens": {
            "type": "integer",
            "description": "Number of tokens used in the prompt",
            "format": "int32"
          },
          "completion_tokens": {
            "type": "integer",
            "description": "Number of tokens generated in the completion",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Token usage statistics for the AI request"
      },
      "PackageDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this package",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name of the package",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Detailed description of the package and its features",
            "nullable": true
          },
          "isArchived": {
            "type": "boolean",
            "description": "When true, prevents new tenants from being assigned to this package"
          },
          "moduleCount": {
            "type": "integer",
            "description": "Number of modules included in this package",
            "format": "int32"
          },
          "tenantCount": {
            "type": "integer",
            "description": "Number of tenants assigned to this package",
            "format": "int32"
          },
          "modules": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CodeAndNameDto"
            },
            "description": "Collection of modules included in this package",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "When the package was created",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "description": "When the package was last updated",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A system-level collection of modules that can be assigned to a tenant"
      },
      "PageSelection": {
        "enum": [
          "None",
          "AllPages",
          "FirstPageOnly",
          "AllExceptFirstPage"
        ],
        "type": "string"
      },
      "PatchMailboxMessageRequest": {
        "required": [
          "isRead",
          "messageIds"
        ],
        "type": "object",
        "properties": {
          "messageIds": {
            "minItems": 1,
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The message UniqueIds to update"
          },
          "isRead": {
            "type": "boolean",
            "description": "Whether the messages should be marked as read"
          }
        },
        "additionalProperties": false,
        "description": "Request to bulk-update mailbox message properties (e.g., mark as read/unread)"
      },
      "PatchTenantUserRequest": {
        "type": "object",
        "properties": {
          "hourlyRate": {
            "maximum": 100000,
            "minimum": 0,
            "type": "number",
            "description": "Charge-out rate per hour for time tracking. Null clears the rate so the practice default applies.",
            "format": "double",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Partial update for a user within a tenant. Every field is optional; the current\nfield set is applied as a unit (send the value you want, null to clear).\nExtend with further patchable fields as needed."
      },
      "PayerDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "nullable": true
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "email": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Simplified DTO for displaying payer (customer) information.\nPayers are created by GoCardless via Billing Request Flow, so we only need read-only properties."
      },
      "PaymentMandateResponse": {
        "type": "object",
        "properties": {
          "status": {
            "$ref": "#/components/schemas/PaymentMandateStatus"
          },
          "scheme": {
            "type": "string",
            "description": "The Direct Debit scheme (e.g., \"bacs\", \"sepa_core\").",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "The date and time when the mandate was created.",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "Response model representing a payment mandate."
      },
      "PaymentMandateStatus": {
        "enum": [
          "PendingCustomerApproval",
          "PendingSubmission",
          "Submitted",
          "Active",
          "Failed",
          "Cancelled",
          "Expired"
        ],
        "type": "string",
        "description": "Defines the status of a GoCardless Direct Debit mandate.\nMaps to GoCardless mandate statuses: pending_customer_approval, pending_submission,\nsubmitted, active, failed, cancelled, expired."
      },
      "PendingWorkflowStepDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "The workflow step ID",
            "format": "int32"
          },
          "stepName": {
            "type": "string",
            "description": "The name of the workflow step",
            "nullable": true
          },
          "stepType": {
            "$ref": "#/components/schemas/WorkflowStepType"
          },
          "status": {
            "$ref": "#/components/schemas/TaskItemStatus"
          },
          "task": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "client": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "taskCategory": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "assignedUser": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "assignedTeam": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "groupName": {
            "type": "string",
            "description": "The workflow group name",
            "nullable": true
          },
          "groupNumber": {
            "type": "integer",
            "description": "The group number within the workflow",
            "format": "int32"
          },
          "stepNumber": {
            "type": "integer",
            "description": "The step number within the group",
            "format": "int32"
          },
          "deadline": {
            "type": "string",
            "description": "The group's calculated deadline (from the task's due date + group interval)",
            "format": "date-time",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "When the step was created",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "Lightweight projection of a manual-mode outbound workflow step that is ready to send.\nThese are steps where dependencies are met and a user needs to review and trigger the send."
      },
      "PendingWorkflowStepDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PendingWorkflowStepDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "PendingWorkflowStepSortField": {
        "enum": [
          "StepName",
          "Deadline",
          "ClientName",
          "StepType"
        ],
        "type": "string"
      },
      "Permission": {
        "enum": [
          "None",
          "ViewOwn",
          "ViewAll",
          "Create",
          "Update",
          "Delete",
          "Assign",
          "Export",
          "Import",
          "Admin"
        ],
        "type": "string"
      },
      "PipelineDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Stable identifier. For library-shipped items this is the library code; for tenant-imported\nitems this is the tenant entity's own code.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name shown to users in lists, dialogs, and the import browser.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Optional human-readable summary of what this entity is for.",
            "nullable": true
          },
          "libraryCode": {
            "type": "string",
            "description": "The Code of the library template this entity was imported from, or null if the entity\nis not from the library. Read-only — cannot be changed once set. Example: \"vat_returns\".",
            "nullable": true
          },
          "libraryStatus": {
            "$ref": "#/components/schemas/LibraryStatus"
          },
          "isImported": {
            "type": "boolean",
            "description": "True if the tenant has already imported this library item."
          },
          "deprecated": {
            "type": "boolean",
            "description": "True if this library item has been retired. Deprecated items are hidden from the import\nbrowser (so new tasks cannot be created from them) but remain available for revert-to-library\non existing imports."
          },
          "isArchived": {
            "type": "boolean",
            "description": "Indicates whether this pipeline is archived (inactive)"
          },
          "defaultManagedByUser": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "showKanbanBoard": {
            "type": "boolean",
            "description": "Whether this pipeline should appear on the Boards kanban view"
          },
          "stages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PipelineStageDto"
            },
            "description": "User-defined stages for this pipeline",
            "nullable": true
          },
          "stageCount": {
            "type": "integer",
            "description": "The number of stages defined on this pipeline",
            "format": "int32"
          },
          "recurringTaskCount": {
            "type": "integer",
            "description": "The number of recurring tasks associated with this pipeline",
            "format": "int32"
          },
          "createdDate": {
            "type": "string",
            "description": "When the pipeline was created",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "description": "When the pipeline was last updated",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response DTO for sales pipeline information"
      },
      "PipelineDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PipelineDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "PipelineOnboardingTaskTemplateDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Stable identifier. For library-shipped items this is the library code; for tenant-imported\nitems this is the tenant entity's own code.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name shown to users in lists, dialogs, and the import browser.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Optional human-readable summary of what this entity is for.",
            "nullable": true
          },
          "libraryCode": {
            "type": "string",
            "description": "The Code of the library template this entity was imported from, or null if the entity\nis not from the library. Read-only — cannot be changed once set. Example: \"vat_returns\".",
            "nullable": true
          },
          "libraryStatus": {
            "$ref": "#/components/schemas/LibraryStatus"
          },
          "isImported": {
            "type": "boolean",
            "description": "True if the tenant has already imported this library item."
          },
          "deprecated": {
            "type": "boolean",
            "description": "True if this library item has been retired. Deprecated items are hidden from the import\nbrowser (so new tasks cannot be created from them) but remain available for revert-to-library\non existing imports."
          },
          "pipeline": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "timeEstimateMinutes": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "dueDateOffsetDays": {
            "type": "integer",
            "description": "Days after the card's start date for the task due date",
            "format": "int32"
          },
          "assignmentType": {
            "$ref": "#/components/schemas/AssignmentType"
          },
          "assignedUser": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "assignedTeam": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "workflow": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "category": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "checklist": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChecklistItemDto"
            },
            "description": "Checklist items for this intake task template",
            "nullable": true
          },
          "active": {
            "type": "boolean",
            "description": "Whether this template is active"
          }
        },
        "additionalProperties": false,
        "description": "DTO for pipeline intake task templates, exposing only codes and enums (never DB IDs)."
      },
      "PipelineOnboardingTaskTemplateDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PipelineOnboardingTaskTemplateDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "PipelineOnboardingTaskTemplateSortField": {
        "enum": [
          "DueDateOffsetDays",
          "Name"
        ],
        "type": "string"
      },
      "PipelineSortField": {
        "enum": [
          "Name"
        ],
        "type": "string"
      },
      "PipelineStageDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this stage",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The display name of this stage",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Optional description of what this stage represents",
            "nullable": true
          },
          "icon": {
            "type": "string",
            "description": "Optional Lucide icon name for visual identification",
            "nullable": true
          },
          "color": {
            "type": "string",
            "description": "Optional hex colour for visual identification",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "The display order for this stage",
            "format": "int32"
          },
          "showOnClientPage": {
            "type": "boolean",
            "description": "Whether a client's pipeline card is shown on their client page while it sits in this stage.\nDefaults to true; turn off for terminal stages (e.g. \"Won\")."
          }
        },
        "additionalProperties": false,
        "description": "DTO for a user-defined stage on a sales pipeline"
      },
      "PlatformCapability": {
        "enum": [
          "None",
          "Accounting",
          "CRM",
          "DocumentManagement",
          "Communication",
          "ProjectManagement",
          "TimeTracking",
          "Payments",
          "ClientImport",
          "DirectDebit",
          "AML",
          "Proposals",
          "HMRC"
        ],
        "type": "string"
      },
      "PortalFolderDto": {
        "type": "object",
        "properties": {
          "folderId": {
            "type": "string",
            "description": "The external platform folder ID",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name of the folder",
            "nullable": true
          },
          "path": {
            "type": "string",
            "description": "Path to pass as portalFolderPath when drilling into this folder.\nFormat: \"/\" separated folder names, e.g. \"Tax Returns/2026\".",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A folder entry for portal document navigation.\nShared between the main API portal-view and client portal folder browsing."
      },
      "PortalUserDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique code identifying the portal user.",
            "nullable": true
          },
          "contactCode": {
            "type": "string",
            "description": "Code of the linked contact.",
            "nullable": true
          },
          "email": {
            "type": "string",
            "description": "The portal user's email address.",
            "nullable": true
          },
          "contactFirstName": {
            "type": "string",
            "description": "First name of the linked contact.",
            "nullable": true
          },
          "contactLastName": {
            "type": "string",
            "description": "Last name of the linked contact.",
            "nullable": true
          },
          "isActive": {
            "type": "boolean",
            "description": "Whether this portal user account is active."
          },
          "isEmailVerified": {
            "type": "boolean",
            "description": "Whether the user's email address has been verified."
          },
          "lastLoginDate": {
            "type": "string",
            "description": "When the portal user last logged in.",
            "format": "date-time",
            "nullable": true
          },
          "invitationSentDate": {
            "type": "string",
            "description": "When the portal invitation email was last sent.",
            "format": "date-time",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "When the portal user was created.",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "A contact who has been granted access to the client portal."
      },
      "PracticeDetailsDto": {
        "required": [
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "minLength": 1,
            "type": "string",
            "description": "Official name of the accounting practice or firm"
          },
          "isVatRegistered": {
            "type": "boolean",
            "description": "Whether the practice is registered for VAT"
          },
          "companyNumber": {
            "type": "string",
            "description": "Companies House registration number (if the practice is a limited company)",
            "nullable": true
          },
          "logoUrl": {
            "type": "string",
            "description": "URL to the practice logo image (from image assets)",
            "nullable": true
          },
          "address": {
            "type": "string",
            "description": "Practice physical/postal address",
            "nullable": true
          },
          "website": {
            "type": "string",
            "description": "Practice website URL",
            "nullable": true
          },
          "email": {
            "type": "string",
            "description": "Practice email address for general inquiries",
            "format": "email",
            "nullable": true
          },
          "mobile": {
            "type": "string",
            "description": "Practice mobile phone number",
            "nullable": true
          },
          "telephone": {
            "type": "string",
            "description": "Practice landline telephone number",
            "nullable": true
          },
          "professionalBody": {
            "$ref": "#/components/schemas/ProfessionalBody"
          },
          "professionalBodyName": {
            "type": "string",
            "description": "Full name of the professional body (e.g. \"Institute of Chartered Accountants in England and Wales\"). Derived from ProfessionalBody.",
            "nullable": true,
            "readOnly": true
          },
          "professionalBodyWebsite": {
            "type": "string",
            "description": "Public website URL for the professional body (e.g. \"https://www.icaew.com\"). Derived from ProfessionalBody.",
            "nullable": true,
            "readOnly": true
          },
          "hmrc": {
            "$ref": "#/components/schemas/PracticeHmrcDetailsDto"
          },
          "logo": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          }
        },
        "additionalProperties": false,
        "description": "Core practice/firm information for the accounting practice or professional services firm.\nUsed for branding, contact details, and professional membership information that appears on proposals,\nengagement letters, and other client-facing documents."
      },
      "PracticeHmrcDetailsDto": {
        "type": "object",
        "properties": {
          "agentReferenceNumber": {
            "maxLength": 20,
            "type": "string",
            "description": "Agent Reference Number (ARN) from the HMRC Agent Services Account. Used for MTD digital authorisations.",
            "nullable": true
          },
          "saAgentCode": {
            "maxLength": 20,
            "type": "string",
            "description": "Self Assessment agent code (e.g. A12345)",
            "nullable": true
          },
          "payeAgentCode": {
            "maxLength": 20,
            "type": "string",
            "description": "PAYE/CIS agent code (e.g. 123/A12345)",
            "nullable": true
          },
          "ctAgentCode": {
            "maxLength": 20,
            "type": "string",
            "description": "Corporation Tax agent code",
            "nullable": true
          },
          "contactFirstName": {
            "maxLength": 100,
            "type": "string",
            "description": "First name of the agent contact person. Included in HMRC XML submissions.",
            "nullable": true
          },
          "contactLastName": {
            "maxLength": 100,
            "type": "string",
            "description": "Last name of the agent contact person. Included in HMRC XML submissions.",
            "nullable": true
          },
          "contactEmail": {
            "maxLength": 255,
            "type": "string",
            "description": "Email of the agent contact person. Included in HMRC XML submissions.",
            "format": "email",
            "nullable": true
          },
          "govGatewayUserId": {
            "type": "string",
            "description": "Government Gateway user ID for HMRC XML API submissions.",
            "nullable": true
          },
          "govGatewayPasswordSet": {
            "type": "boolean",
            "description": "Whether a Government Gateway password is stored."
          },
          "govGatewayPassword": {
            "type": "string",
            "description": "Government Gateway password (write-only). Set to update, empty string to clear, null to leave unchanged.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "HMRC-specific settings for the practice, used for agent authorisation submissions."
      },
      "PresetDateRange": {
        "enum": [
          "ThisWeek",
          "NextWeek",
          "Last7Days",
          "Next7Days",
          "Last30Days",
          "Next30Days",
          "PreviousMonth",
          "ThisMonth",
          "NextMonth",
          "PreviousQuarter",
          "ThisQuarter",
          "NextQuarter",
          "PreviousYear",
          "ThisYear",
          "NextYear",
          "YearToDate",
          "PreviousFinancialYear",
          "ThisFinancialYear",
          "NextFinancialYear",
          "FinancialYearToDate",
          "Today",
          "CustomDateRange"
        ],
        "type": "string"
      },
      "PriceAdjustmentType": {
        "enum": [
          "Percentage",
          "FixedAmount"
        ],
        "type": "string"
      },
      "PricingFactorDto": {
        "type": "object",
        "properties": {
          "description": {
            "type": "string",
            "description": "The description of the pricing factor (e.g., \"What bookkeeping software does the client use?\")",
            "nullable": true
          },
          "adjustmentType": {
            "$ref": "#/components/schemas/PriceAdjustmentType"
          },
          "options": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PricingFactorOptionDto"
            },
            "description": "The available options for this pricing factor",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "DTO for pricing factor information"
      },
      "PricingFactorOptionDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The name of the option (e.g., \"None\", \"Xero\", \"Good\", \"Bad\")",
            "nullable": true
          },
          "value": {
            "type": "number",
            "description": "The value adjustment for this option. Interpretation depends on the parent factor's AdjustmentType:\nPercentage → multiplier (0.4 = +40%, -0.2 = -20%); FixedAmount → absolute currency (10 = +£10).",
            "format": "double"
          }
        },
        "additionalProperties": false,
        "description": "DTO for pricing factor option information"
      },
      "PricingTierDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this pricing tier",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name of the pricing tier",
            "nullable": true
          },
          "minClients": {
            "type": "integer",
            "description": "Minimum number of clients for this tier",
            "format": "int32"
          },
          "maxClients": {
            "type": "integer",
            "description": "Maximum number of clients for this tier (null for unlimited)",
            "format": "int32",
            "nullable": true
          },
          "monthlyPricePence": {
            "type": "integer",
            "description": "Monthly price in pence",
            "format": "int32"
          },
          "isPrivate": {
            "type": "boolean",
            "description": "Whether this tier is private. Private tiers can only be assigned by SuperAdmins.\nOmitted from response when false."
          }
        },
        "additionalProperties": false,
        "description": "Response DTO for pricing tier information"
      },
      "ProblemDetails": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "nullable": true
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "detail": {
            "type": "string",
            "nullable": true
          },
          "instance": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": {}
      },
      "ProcessInvitationRequest": {
        "required": [
          "accept",
          "tenantCode",
          "token"
        ],
        "type": "object",
        "properties": {
          "token": {
            "minLength": 1,
            "type": "string",
            "description": "The invitation token received in the invitation email"
          },
          "tenantCode": {
            "minLength": 1,
            "type": "string",
            "description": "The tenant code that the user is being invited to"
          },
          "accept": {
            "type": "boolean",
            "description": "Whether to accept or decline the invitation"
          }
        },
        "additionalProperties": false,
        "description": "Request model for processing a user invitation response to join a tenant"
      },
      "ProcessInvitationResponse": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string",
            "description": "Message indicating the result of the invitation processing",
            "nullable": true
          },
          "tenantCode": {
            "type": "string",
            "description": "The tenant code for the invitation",
            "nullable": true
          },
          "userCode": {
            "type": "string",
            "description": "The user's code within the tenant",
            "nullable": true
          },
          "status": {
            "type": "string",
            "description": "The current status of the invitation (Active or Declined)",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response model for processing an invitation (accept or decline)"
      },
      "ProfessionalBody": {
        "enum": [
          "ICAEW",
          "ICAS",
          "CAI",
          "ACCA",
          "CIPFA",
          "CIMA",
          "AIA",
          "CIOT",
          "ATT",
          "AAT",
          "CPAA",
          "ICB",
          "IAB",
          "HMRC",
          "IFA"
        ],
        "type": "string"
      },
      "ProfessionalClearanceLetterSettingsDto": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "Whether professional clearance letter functionality is enabled for this tenant"
          },
          "emailContentBlock": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "ccRecipientConfig": {
            "$ref": "#/components/schemas/EmailRecipientConfig"
          }
        },
        "additionalProperties": false,
        "description": "Tenant-level settings for professional clearance letters"
      },
      "ProfessionalClearanceRequestItemDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this professional clearance request",
            "nullable": true
          },
          "request": {
            "type": "string",
            "description": "The request text",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "The sort order for displaying the requests",
            "format": "int32"
          },
          "global": {
            "type": "boolean",
            "description": "If true, this item will be included for all clients regardless of the services they have"
          }
        },
        "additionalProperties": false,
        "description": "An individual item within a professional clearance request during client onboarding"
      },
      "ProfessionalClearanceRequestItemDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProfessionalClearanceRequestItemDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "ProfessionalClearanceRequestItemSortField": {
        "enum": [
          "SortOrder"
        ],
        "type": "string"
      },
      "ProviderType": {
        "enum": [
          "Smtp",
          "SendGrid",
          "Microsoft365",
          "Google"
        ],
        "type": "string",
        "description": "Represents the type of email provider"
      },
      "ReconnectOAuthRequest": {
        "required": [
          "returnUrl"
        ],
        "type": "object",
        "properties": {
          "returnUrl": {
            "minLength": 1,
            "type": "string",
            "description": "URL to redirect the user back to after completing the OAuth flow"
          }
        },
        "additionalProperties": false,
        "description": "Request to initiate OAuth reconnection for an expired or scope-upgraded configuration"
      },
      "ReconnectOAuthResponse": {
        "type": "object",
        "properties": {
          "authorisationUrl": {
            "type": "string",
            "description": "The OAuth authorisation URL to redirect the user to",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response containing the OAuth authorisation URL for reconnecting a configuration"
      },
      "RecurrenceConfigDto": {
        "type": "object",
        "properties": {
          "every": {
            "type": "integer",
            "description": "Interval value (e.g., 1 for every month, 2 for every 2 months)",
            "format": "int32"
          },
          "unit": {
            "$ref": "#/components/schemas/RecurrenceUnit"
          },
          "inMonths": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MonthFlags"
            },
            "description": "Which months to run in. Only valid when Unit is Year.\nExample: [\"January\", \"April\", \"July\", \"October\"] for quarterly",
            "nullable": true
          },
          "weekDaysOnly": {
            "type": "boolean",
            "description": "If true, skip weekends for daily patterns. Only valid when Unit is Day."
          }
        },
        "additionalProperties": false,
        "description": "Configuration for how often a recurring task repeats."
      },
      "RecurrenceUnit": {
        "enum": [
          "Day",
          "Week",
          "Month",
          "Year"
        ],
        "type": "string"
      },
      "RecurringTaskItemDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Stable identifier. For library-shipped items this is the library code; for tenant-imported\nitems this is the tenant entity's own code.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name shown to users in lists, dialogs, and the import browser.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Optional human-readable summary of what this entity is for.",
            "nullable": true
          },
          "libraryCode": {
            "type": "string",
            "description": "The Code of the library template this entity was imported from, or null if the entity\nis not from the library. Read-only — cannot be changed once set. Example: \"vat_returns\".",
            "nullable": true
          },
          "libraryStatus": {
            "$ref": "#/components/schemas/LibraryStatus"
          },
          "isImported": {
            "type": "boolean",
            "description": "True if the tenant has already imported this library item."
          },
          "deprecated": {
            "type": "boolean",
            "description": "True if this library item has been retired. Deprecated items are hidden from the import\nbrowser (so new tasks cannot be created from them) but remain available for revert-to-library\non existing imports."
          },
          "timeEstimateMinutes": {
            "type": "integer",
            "description": "The estimated time to complete each generated task, in whole minutes.",
            "format": "int32",
            "nullable": true
          },
          "assignedUser": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "assignedTeam": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "billableService": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "sortOrder": {
            "type": "integer",
            "description": "Sort order for displaying recurring tasks.",
            "format": "int32",
            "nullable": true
          },
          "active": {
            "type": "boolean",
            "description": "Whether this recurring task is active and will generate new tasks."
          },
          "taskStartConfig": {
            "$ref": "#/components/schemas/TaskStartConfigDto"
          },
          "recurrence": {
            "$ref": "#/components/schemas/RecurrenceConfigDto"
          },
          "dueDateConfig": {
            "$ref": "#/components/schemas/DueDateConfigDto"
          },
          "statutoryDateConfig": {
            "$ref": "#/components/schemas/StatutoryDateConfigDto"
          },
          "taskDateBasis": {
            "$ref": "#/components/schemas/TaskDateBasis"
          },
          "startHolidayAdjustment": {
            "$ref": "#/components/schemas/HolidayAdjustment"
          },
          "dueHolidayAdjustment": {
            "$ref": "#/components/schemas/HolidayAdjustment"
          },
          "assignmentType": {
            "$ref": "#/components/schemas/AssignmentType"
          },
          "workflow": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "category": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "clientAssociationType": {
            "$ref": "#/components/schemas/ClientAssociationType"
          },
          "vatReportingPeriod": {
            "$ref": "#/components/schemas/VatReportingPeriod"
          },
          "nextRunDate": {
            "type": "string",
            "description": "The next date this recurring task should be created (for display purposes)",
            "format": "date-time",
            "nullable": true
          },
          "checklist": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChecklistItemDto"
            },
            "description": "Checklist items for this recurring task template",
            "nullable": true
          },
          "taskNameTemplate": {
            "type": "string",
            "description": "Optional template for naming tasks created from this recurring task.\nSupports {{ token }} placeholders (e.g. \"VAT Return - {{ ClientName }} - {{ Quarter }} {{ Year }}\").\nWhen null or empty, tasks use the recurring task's Name.\nAvailable tokens can be retrieved from the GET /metadata/task-name-tokens endpoint.\nUnrecognised tokens are left as-is in generated task names.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "DTO for recurring task templates, exposing only codes and enums."
      },
      "RecurringTaskItemDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RecurringTaskItemDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "RecurringTaskItemSortField": {
        "enum": [
          "Name",
          "NextRunDate"
        ],
        "type": "string"
      },
      "RedeemDiscountCodeRequest": {
        "required": [
          "code"
        ],
        "type": "object",
        "properties": {
          "code": {
            "maxLength": 50,
            "minLength": 0,
            "type": "string",
            "description": "The discount code to redeem (e.g. \"LAUNCH50\")."
          }
        },
        "additionalProperties": false,
        "description": "Request to redeem a discount code for a tenant's subscription."
      },
      "RenderContentBlockRequest": {
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/TemplateVariables"
          },
          "includeEmailBranding": {
            "type": "boolean",
            "description": "When true, wraps the rendered body with the tenant's email header, footer, and design theme\nfrom Email Settings. Use for email previews."
          }
        },
        "additionalProperties": false,
        "description": "Request to render a content block's body HTML with template variables.\nOptionally wraps the rendered body with the tenant's email header, footer, and design theme."
      },
      "RenderDocumentTemplateRequest": {
        "type": "object",
        "properties": {
          "designThemeCode": {
            "type": "string",
            "description": "Optional design theme code to override the template's default theme.\nPriority: Request theme > Template default > Tenant default",
            "nullable": true
          },
          "data": {
            "$ref": "#/components/schemas/TemplateVariables"
          }
        },
        "additionalProperties": false,
        "description": "Request to render a document template with dynamic data.\nThe template will be processed with the provided data to generate final HTML output."
      },
      "RenderTemplateStringRequest": {
        "required": [
          "template"
        ],
        "type": "object",
        "properties": {
          "template": {
            "minLength": 1,
            "type": "string",
            "description": "The Liquid template string to render (e.g. a subject line like \"Professional Clearance for {{ Client.Name }}\")"
          },
          "data": {
            "$ref": "#/components/schemas/TemplateVariables"
          }
        },
        "additionalProperties": false,
        "description": "Request to render an arbitrary Liquid template string with the provided variables.\nUse for rendering subject lines or other template strings outside of content blocks."
      },
      "ReplyEmailRequest": {
        "required": [
          "htmlBody"
        ],
        "type": "object",
        "properties": {
          "htmlBody": {
            "minLength": 1,
            "type": "string",
            "description": "HTML body of the reply"
          },
          "plainTextBody": {
            "type": "string",
            "description": "Plain text body (optional fallback)",
            "nullable": true
          },
          "replyAll": {
            "type": "boolean",
            "description": "Whether to reply to all recipients (default: false = reply to sender only)"
          },
          "toRecipients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmailRecipientDto"
            },
            "description": "Override To recipients. Null = use provider default (original sender for reply, all for reply-all).\nEmpty list = explicitly no To recipients.",
            "nullable": true
          },
          "ccRecipients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmailRecipientDto"
            },
            "description": "Override CC recipients. Null = use provider default.\nEmpty list = explicitly no CC recipients (useful for removing CC on reply-all).",
            "nullable": true
          },
          "bccRecipients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmailRecipientDto"
            },
            "description": "BCC recipients. Null or empty = no BCC (providers never auto-populate BCC).",
            "nullable": true
          },
          "attachments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmailAttachmentDto"
            },
            "description": "Attachments to include in the reply. Null or empty = no attachments.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request to reply to a mailbox email.\nAll fields except HtmlBody are optional — omit them to use provider defaults."
      },
      "ReplyEmailResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "description": "Whether the reply was sent successfully"
          },
          "errorMessage": {
            "type": "string",
            "description": "Error message if the reply failed",
            "nullable": true
          },
          "reconnectRequired": {
            "type": "boolean",
            "description": "Whether the user needs to reconnect their mailbox"
          }
        },
        "additionalProperties": false,
        "description": "Response after replying to a mailbox email"
      },
      "ReportGroupKind": {
        "enum": [
          "Service",
          "Client",
          "User",
          "Team",
          "StepType",
          "AgeBucket",
          "Status",
          "CurrentStep",
          "None",
          "Month",
          "Unassigned"
        ],
        "type": "string"
      },
      "RequestClientApprovalRequest": {
        "type": "object",
        "properties": {
          "recipientEmails": {
            "type": "string",
            "description": "Comma-separated email addresses of recipients to send the approval request to",
            "nullable": true
          },
          "chaseFrequencyDays": {
            "type": "integer",
            "description": "Override for the chase frequency in days. If not specified, the tenant default is used.",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request to send a document approval request to specified recipients"
      },
      "ResendDataFormRequestRequest": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string",
            "description": "A message explaining what the client needs to do, included in the notification email.\nIf not specified, the original message is used.",
            "nullable": true
          },
          "recipients": {
            "$ref": "#/components/schemas/EmailRecipientConfig"
          }
        },
        "additionalProperties": false,
        "description": "DTO for resending the notification email for a form request"
      },
      "ResendVerificationResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "description": "Whether the resend was successful"
          },
          "message": {
            "type": "string",
            "description": "A message describing the result",
            "nullable": true
          },
          "errorCode": {
            "type": "string",
            "description": "Error code for client handling",
            "nullable": true
          },
          "userEmail": {
            "type": "string",
            "description": "The email address the verification was sent to (only included on success)",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response DTO for resending verification email"
      },
      "RevenueRangeDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this revenue range",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The display name of the revenue range (e.g., \"£30k - £70k\")",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "The sort order for displaying revenue ranges",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "A revenue band used for tiered service pricing"
      },
      "RevenueRangeDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RevenueRangeDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "RevenueRangeSortField": {
        "enum": [
          "SortOrder",
          "Name"
        ],
        "type": "string"
      },
      "ReviewClientDocumentRequest": {
        "type": "object",
        "properties": {
          "reviewStatus": {
            "$ref": "#/components/schemas/ReviewStatus"
          }
        },
        "additionalProperties": false,
        "description": "Request to approve or reject a client-uploaded document"
      },
      "ReviewDataFormAnswerRequest": {
        "type": "object",
        "properties": {
          "accepted": {
            "type": "boolean",
            "description": "True to accept and apply the value, false to reject."
          },
          "value": {
            "type": "string",
            "description": "Optional edited value to use instead of the original answer when accepting.\nIgnored when rejecting.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request body for reviewing (accepting/rejecting) a single form answer."
      },
      "ReviewDocumentRequestResponseRequest": {
        "type": "object",
        "properties": {
          "accepted": {
            "type": "boolean",
            "description": "Whether to accept the submission. If false, NextAction determines what happens."
          },
          "reviewNote": {
            "type": "string",
            "description": "Note from the reviewer explaining the decision",
            "nullable": true
          },
          "nextAction": {
            "$ref": "#/components/schemas/DocumentRequestRejectAction"
          },
          "makeDocumentsAvailable": {
            "type": "boolean",
            "description": "When accepting, whether to publish the request's documents to the main Documents list.\nDefaults to true. Only used when Accepted is true."
          },
          "portalFolderPath": {
            "type": "string",
            "description": "When publishing, the portal folder path where the documents should appear.\nNull or omitted means the client root. Only used when MakeDocumentsAvailable is true.\nFormat: \"/\" separated folder names, e.g. \"Tax Returns/2026\".",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for reviewing (accepting or rejecting) a document request response"
      },
      "ReviewStatus": {
        "enum": [
          "Approved",
          "PendingReview",
          "Rejected"
        ],
        "type": "string"
      },
      "RoleInfo": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The display name of the user's role within this tenant",
            "nullable": true
          },
          "type": {
            "$ref": "#/components/schemas/RoleType"
          },
          "isOwner": {
            "type": "boolean",
            "description": "Whether the user is the owner of the tenant.\nThis is computed from Tenant.OwnerUserId."
          },
          "isClientManager": {
            "type": "boolean",
            "description": "Whether the user is a client manager within the tenant"
          },
          "isPartner": {
            "type": "boolean",
            "description": "Whether the user is a partner within the tenant"
          },
          "isAssociate": {
            "type": "boolean",
            "description": "Whether the user is an associate within the tenant"
          },
          "isRestrictedToTeamClients": {
            "type": "boolean",
            "description": "Whether the user can only see clients belonging to their teams"
          },
          "isRestrictedToAssignedClients": {
            "type": "boolean",
            "description": "Whether the user can only see clients where they are Manager, Partner, or Associate"
          },
          "teams": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CodeAndNameDto"
            },
            "description": "Teams the user is a member of",
            "nullable": true
          },
          "permissions": {
            "type": "object",
            "properties": {
              "Tasks": {
                "$ref": "#/components/schemas/Permission"
              },
              "Users": {
                "$ref": "#/components/schemas/Permission"
              },
              "Clients": {
                "$ref": "#/components/schemas/Permission"
              },
              "Contacts": {
                "$ref": "#/components/schemas/Permission"
              },
              "ClientContacts": {
                "$ref": "#/components/schemas/Permission"
              },
              "Reports": {
                "$ref": "#/components/schemas/Permission"
              },
              "Settings": {
                "$ref": "#/components/schemas/Permission"
              },
              "ApiKeys": {
                "$ref": "#/components/schemas/Permission"
              },
              "Roles": {
                "$ref": "#/components/schemas/Permission"
              },
              "BillableServices": {
                "$ref": "#/components/schemas/Permission"
              },
              "ClientBillableServices": {
                "$ref": "#/components/schemas/Permission"
              },
              "ServicePackages": {
                "$ref": "#/components/schemas/Permission"
              },
              "RecurringTasks": {
                "$ref": "#/components/schemas/Permission"
              },
              "Workflows": {
                "$ref": "#/components/schemas/Permission"
              },
              "ThirdPartyConnections": {
                "$ref": "#/components/schemas/Permission"
              },
              "ContentBlocks": {
                "$ref": "#/components/schemas/Permission"
              },
              "PracticeDetails": {
                "$ref": "#/components/schemas/Permission"
              },
              "DesignThemes": {
                "$ref": "#/components/schemas/Permission"
              },
              "Templates": {
                "$ref": "#/components/schemas/Permission"
              },
              "ClientDocuments": {
                "$ref": "#/components/schemas/Permission"
              },
              "Engagements": {
                "$ref": "#/components/schemas/Permission"
              },
              "CustomFields": {
                "$ref": "#/components/schemas/Permission"
              },
              "Subscription": {
                "$ref": "#/components/schemas/Permission"
              },
              "ClientPortalSettings": {
                "$ref": "#/components/schemas/Permission"
              },
              "DocumentRequests": {
                "$ref": "#/components/schemas/Permission"
              },
              "Billing": {
                "$ref": "#/components/schemas/Permission"
              },
              "ClientEmailRules": {
                "$ref": "#/components/schemas/Permission"
              },
              "Mailbox": {
                "$ref": "#/components/schemas/Permission"
              },
              "Teams": {
                "$ref": "#/components/schemas/Permission"
              },
              "DataForms": {
                "$ref": "#/components/schemas/Permission"
              },
              "KanbanBoards": {
                "$ref": "#/components/schemas/Permission"
              },
              "ClientBilling": {
                "$ref": "#/components/schemas/Permission"
              },
              "EmailBroadcasts": {
                "$ref": "#/components/schemas/Permission"
              },
              "TimeTracking": {
                "$ref": "#/components/schemas/Permission"
              },
              "Pipelines": {
                "$ref": "#/components/schemas/Permission"
              }
            },
            "additionalProperties": false,
            "description": "Dictionary of permissions for each permissible entity (Clients, Tasks, etc.) within the tenant",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Information about a user's role within a tenant, including permissions and special designations"
      },
      "RoleType": {
        "enum": [
          "System",
          "Custom"
        ],
        "type": "string"
      },
      "RunningTimerDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique code for the timer",
            "nullable": true
          },
          "user": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "startedAt": {
            "type": "string",
            "description": "When the timer was first started (UTC) — the start of its first block",
            "format": "date-time"
          },
          "blocks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TimerBlockDto"
            },
            "description": "The blocks of work accrued as the timer is paused and resumed. The block\nwith no end time is the one currently running; none open means the timer\nis paused. Elapsed working time is the sum of the blocks.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "What the time is being spent on",
            "nullable": true
          },
          "isBillable": {
            "type": "boolean",
            "description": "Whether the logged time will be billable — carried onto the entry when the timer stops"
          },
          "client": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "taskItem": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "workflowStep": {
            "$ref": "#/components/schemas/LinkedWorkflowStepDto"
          }
        },
        "additionalProperties": false,
        "description": "The calling user's live timer"
      },
      "SalesPipelineSettingsDto": {
        "type": "object",
        "properties": {
          "isEnabled": {
            "type": "boolean",
            "description": "Whether the Sales Pipeline feature is enabled for this tenant. When off (the default), the\npipeline UI is hidden and no pipeline automations run. When on, Active Prospects are also\nincluded in the tenant's billable client count (affecting subscription tier and pricing)."
          }
        },
        "additionalProperties": false,
        "description": "Tenant-level settings for the Sales Pipeline feature."
      },
      "SaveClientDateDto": {
        "type": "object",
        "properties": {
          "dateType": {
            "$ref": "#/components/schemas/ClientDateType"
          },
          "date": {
            "type": "string",
            "description": "The date value to set for this client date type",
            "format": "date",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for creating or updating an important client date.\nUsed to set dates like year-end, accounts due, or VAT return deadlines that drive recurring task generation."
      },
      "SaveWorkflowStepClientDataRequest": {
        "type": "object",
        "properties": {
          "values": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowStepClientDataValueDto"
            },
            "description": "The field values to save to the client record.",
            "nullable": true
          },
          "markComplete": {
            "type": "boolean",
            "description": "Whether to mark the step as Completed after saving.\nWhen true, required field validation is enforced."
          }
        },
        "additionalProperties": false,
        "description": "Request to save client data values from an UpdateClientData workflow step."
      },
      "SavedClientFilterDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique identifier within the tenant",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "User-friendly name for this saved filter",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Optional description providing more details about this filter's purpose",
            "nullable": true
          },
          "includeInMenu": {
            "type": "boolean",
            "description": "Whether the current user has this filter in their menu/quick access list.\nThis is a per-user preference — other users of a shared filter have their own setting."
          },
          "isShared": {
            "type": "boolean",
            "description": "Whether this filter is shared with all users in the tenant. Shared filters are\nvisible (read-only) to everyone; only the owner can modify or delete them."
          },
          "isOwner": {
            "type": "boolean",
            "description": "Whether the current user owns this filter"
          },
          "owner": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "managerCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by manager code(s)",
            "nullable": true
          },
          "partnerCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by partner code(s)",
            "nullable": true
          },
          "associateCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by associate code(s)",
            "nullable": true
          },
          "statuses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientStatus"
            },
            "description": "Filter by client status(es)",
            "nullable": true
          },
          "types": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientType"
            },
            "description": "Filter by client type(s)",
            "nullable": true
          },
          "serviceCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by billable service code(s)",
            "nullable": true
          },
          "packageCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by service package code(s)",
            "nullable": true
          },
          "teamCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by team code(s)",
            "nullable": true
          },
          "serviceStageCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by service stage composite codes (format: \"serviceCode:stageCode\")",
            "nullable": true
          },
          "defaultSortField": {
            "$ref": "#/components/schemas/ClientSortField"
          },
          "defaultSortDesc": {
            "type": "boolean",
            "description": "Sort in descending order (true) or ascending order (false)",
            "nullable": true
          },
          "iconName": {
            "type": "string",
            "description": "Optional Lucide icon name for visual identification (e.g., \"Calendar\", \"Users\", \"Star\")",
            "nullable": true
          },
          "color": {
            "type": "string",
            "description": "Optional hex color for visual identification (e.g., \"#FF5733\")",
            "nullable": true
          },
          "columnConfigJson": {
            "type": "string",
            "description": "Optional JSON column configuration for the saved view.\nWhen set, overrides the user's default client column preferences.",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "When the filter was created",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "description": "When the filter was last updated",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A saved client filter belonging to a tenant user, defining reusable criteria for filtering client lists"
      },
      "SavedClientFilterDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SavedClientFilterDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "SavedClientFilterSortField": {
        "enum": [
          "Name",
          "UpdatedDate"
        ],
        "type": "string"
      },
      "SavedTaskFilterDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique identifier within the tenant",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "User-friendly name for this saved filter",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Optional description providing more details about this filter's purpose",
            "nullable": true
          },
          "includeInMenu": {
            "type": "boolean",
            "description": "Whether the current user has this filter in their menu/quick access list.\nThis is a per-user preference — other users of a shared filter have their own setting."
          },
          "isShared": {
            "type": "boolean",
            "description": "Whether this filter is shared with all users in the tenant. Shared filters are\nvisible (read-only) to everyone; only the owner can modify or delete them."
          },
          "isOwner": {
            "type": "boolean",
            "description": "Whether the current user owns this filter"
          },
          "owner": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "dateRange": {
            "$ref": "#/components/schemas/PresetDateRange"
          },
          "startDate": {
            "type": "string",
            "description": "Custom start date (only used when DateRange = CustomDateRange)",
            "format": "date",
            "nullable": true
          },
          "endDate": {
            "type": "string",
            "description": "Custom end date (only used when DateRange = CustomDateRange)",
            "format": "date",
            "nullable": true
          },
          "dateBasis": {
            "$ref": "#/components/schemas/TaskDateBasis"
          },
          "clientCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by client code(s)",
            "nullable": true
          },
          "userCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by user code(s)",
            "nullable": true
          },
          "recurringTaskCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by recurring task code(s)",
            "nullable": true
          },
          "categoryCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by category code(s)",
            "nullable": true
          },
          "teamCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by team code(s)",
            "nullable": true
          },
          "statuses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TaskItemStatus"
            },
            "description": "Filter by task status(es)",
            "nullable": true
          },
          "isOverdue": {
            "type": "boolean",
            "description": "Filter to only overdue tasks",
            "nullable": true
          },
          "isUnassigned": {
            "type": "boolean",
            "description": "Include tasks with no assigned user. Can be combined with UserCodes to show\ntasks that are either unassigned OR assigned to specific users.",
            "nullable": true
          },
          "includeProjected": {
            "type": "boolean",
            "description": "Include projected (virtual) tasks in the results"
          },
          "includeWorkflowSteps": {
            "type": "boolean",
            "description": "Include workflow steps in the results (Agenda mode)"
          },
          "defaultSortField": {
            "$ref": "#/components/schemas/TaskItemSortField"
          },
          "defaultSortDesc": {
            "type": "boolean",
            "description": "Sort in descending order (true) or ascending order (false)",
            "nullable": true
          },
          "iconName": {
            "type": "string",
            "description": "Optional Lucide icon name for visual identification (e.g., \"Calendar\", \"Users\", \"Star\")",
            "nullable": true
          },
          "color": {
            "type": "string",
            "description": "Optional hex color for visual identification (e.g., \"#FF5733\")",
            "nullable": true
          },
          "columnConfigJson": {
            "type": "string",
            "description": "Optional JSON column configuration for the saved view.\nWhen set, overrides the user's default task column preferences.",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "When the filter was created",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "description": "When the filter was last updated",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A saved task filter belonging to a tenant user, defining reusable criteria for filtering task lists"
      },
      "SavedTaskFilterDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SavedTaskFilterDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "SavedTaskFilterSortField": {
        "enum": [
          "Name",
          "UpdatedDate"
        ],
        "type": "string"
      },
      "SendDataFormExecutionStateDto": {
        "type": "object",
        "properties": {
          "dataFormRequestCode": {
            "type": "string",
            "description": "The code of the created data form request.",
            "nullable": true
          },
          "clientCode": {
            "type": "string",
            "description": "The client code the form was sent to.",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "description": "UTC timestamp of when the form request was created.",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "Execution state for a SendDataForm workflow step.\nContains information about the created data form request after execution."
      },
      "SendDataFormRequest": {
        "type": "object",
        "properties": {
          "clientCode": {
            "type": "string",
            "description": "The code of the client to send the form to",
            "nullable": true
          },
          "notifyUserCode": {
            "type": "string",
            "description": "The user to notify when the client submits their response. If not specified, no notification is sent.",
            "nullable": true
          },
          "autoAcceptData": {
            "type": "boolean",
            "description": "When true, submitted data will be automatically accepted and copied to the client record without manual review"
          },
          "message": {
            "type": "string",
            "description": "A message explaining what the client needs to do, included in the notification email",
            "nullable": true
          },
          "recipients": {
            "$ref": "#/components/schemas/EmailRecipientConfig"
          },
          "chaseFrequencyDays": {
            "type": "integer",
            "description": "Override for the chase frequency in days. If not specified, the tenant default is used.",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "DTO for sending a form to a single client"
      },
      "SendDataFormStepConfigDto": {
        "type": "object",
        "properties": {
          "dataForm": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "message": {
            "type": "string",
            "description": "Optional message override. When null, the form's DefaultMessage is used.",
            "nullable": true
          },
          "autoAcceptData": {
            "type": "boolean",
            "description": "Whether submitted data is automatically accepted without manual review."
          },
          "notifyAssigneeOnSubmission": {
            "type": "boolean",
            "description": "Whether to send a platform notification to the step's assigned user when the client submits."
          },
          "recipientContactTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientContactType"
            },
            "description": "Client contact types to send the form notification email to.",
            "nullable": true
          },
          "additionalEmailAddresses": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Static email addresses to send the form notification to.",
            "nullable": true
          },
          "chaseFrequencyDays": {
            "type": "integer",
            "description": "Override for how often (in days) to chase this form request.\nWhen null, the tenant-level default is used.",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Configuration for SendDataForm workflow steps.\nUsed for both workflow template definition and task workflow step instance customization."
      },
      "SendDirectDebitSetupEmailRequest": {
        "required": [
          "email"
        ],
        "type": "object",
        "properties": {
          "clientCode": {
            "type": "string",
            "nullable": true
          },
          "email": {
            "minLength": 1,
            "type": "string",
            "format": "email"
          },
          "firstName": {
            "type": "string",
            "nullable": true
          },
          "lastName": {
            "type": "string",
            "nullable": true
          },
          "callbackUrl": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "SendEmailResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "description": "Indicates if the request was accepted"
          },
          "messageId": {
            "type": "string",
            "description": "Unique ID of the queued message",
            "format": "uuid",
            "nullable": true
          },
          "errorMessage": {
            "type": "string",
            "description": "Error message if request failed",
            "nullable": true
          },
          "validationErrors": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Validation errors if any",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response from send email request"
      },
      "SendHmrcAuthorisationRequestDto": {
        "required": [
          "authorisationTypes"
        ],
        "type": "object",
        "properties": {
          "authorisationTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AgentAuthorisationType"
            },
            "description": "The auth types to request (must have an [HmrcDigitalAuth] attribute)"
          },
          "clientId": {
            "type": "string",
            "description": "The HMRC client identifier (NINO for MTD-IT, VRN for MTD-VAT).\nRequired for digital flow types. Ignored for letter-based types (resolved from client data).",
            "nullable": true
          },
          "knownFact": {
            "type": "string",
            "description": "The known fact for verification (postcode for MTD-IT, VAT reg date for MTD-VAT).\nRequired for digital flow types. Ignored for letter-based types.",
            "nullable": true
          },
          "recipientEmails": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Email addresses to send the authorisation links to. Not required if SuppressEmail is true.",
            "nullable": true
          },
          "postcode": {
            "type": "string",
            "description": "The client's postcode. Used for SA and CT letter-based requests (required by HMRC schema).\nIf not provided, extracted from the client's contact address.",
            "nullable": true
          },
          "nino": {
            "type": "string",
            "description": "National Insurance number. Used for SA letter-based requests (optional).\nIf not provided, resolved from the client's main contact.",
            "nullable": true
          },
          "accountsOfficeRef": {
            "type": "string",
            "description": "Accounts Office Reference. Used for PAYE and CIS letter-based requests.\nIf not provided, resolved from the client's business details.",
            "nullable": true
          },
          "companyRegNumber": {
            "type": "string",
            "description": "Companies House registration number. Used for CT letter-based requests.\nIf not provided, resolved from the client's business details.",
            "nullable": true
          },
          "yourReference": {
            "type": "string",
            "description": "Your internal reference for this client. Used in all letter-based requests.\nIf not provided, defaults to InternalReference or client code.",
            "nullable": true
          },
          "suppressEmail": {
            "type": "boolean",
            "description": "If true, create the invitations with HMRC but do not send the email to the client."
          }
        },
        "additionalProperties": false,
        "description": "Request to send HMRC agent authorisation requests for multiple types at once.\nSupports both digital (MTD) and letter-based (SA, CT, PAYE/CIS) flows transparently."
      },
      "SendInvitationRequest": {
        "required": [
          "email",
          "tenantCode"
        ],
        "type": "object",
        "properties": {
          "email": {
            "minLength": 1,
            "type": "string",
            "description": "The email address of the user to send the invitation to",
            "format": "email"
          },
          "tenantCode": {
            "minLength": 1,
            "type": "string",
            "description": "The tenant code for the invitation"
          }
        },
        "additionalProperties": false,
        "description": "Request model for sending an invitation to a user"
      },
      "SendMailboxEmailRequest": {
        "required": [
          "to"
        ],
        "type": "object",
        "properties": {
          "subject": {
            "type": "string",
            "description": "Email subject line (optional; defaults to an empty subject when omitted)",
            "nullable": true
          },
          "htmlBody": {
            "type": "string",
            "description": "HTML body of the email",
            "nullable": true
          },
          "plainTextBody": {
            "type": "string",
            "description": "Plain text body of the email (used as fallback when HTML is not supported)",
            "nullable": true
          },
          "to": {
            "minItems": 1,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmailRecipientDto"
            },
            "description": "List of To recipients (at least one required)"
          },
          "cc": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmailRecipientDto"
            },
            "description": "List of CC recipients (optional)",
            "nullable": true
          },
          "bcc": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmailRecipientDto"
            },
            "description": "List of BCC recipients (optional)",
            "nullable": true
          },
          "attachments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmailAttachmentDto"
            },
            "description": "List of attachments as base64-encoded content (optional)",
            "nullable": true
          },
          "addHeaderFooter": {
            "type": "boolean",
            "description": "Whether to wrap the body with the tenant's configured header/footer before sending. Defaults to false when omitted."
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for sending a new email from a tenant's connected mailbox."
      },
      "ServiceBulkUpdateResult": {
        "type": "object",
        "properties": {
          "updatedCount": {
            "type": "integer",
            "format": "int32"
          },
          "skippedPackageCount": {
            "type": "integer",
            "format": "int32"
          }
        },
        "additionalProperties": false
      },
      "ServiceCategory": {
        "enum": [
          "Other",
          "CoreAccounting",
          "Tax",
          "Payroll",
          "CompanySecretarial",
          "Advisory",
          "SoftwareAndTraining"
        ],
        "type": "string"
      },
      "ServiceDeliveryReportDto": {
        "type": "object",
        "properties": {
          "summary": {
            "$ref": "#/components/schemas/ServiceDeliverySummaryDto"
          },
          "rows": {
            "$ref": "#/components/schemas/ServiceDeliveryRowDtoPagedResult"
          },
          "generatedAt": {
            "type": "string",
            "description": "UTC timestamp the report was computed - the report is a point-in-time snapshot, not live.",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "The Service Delivery Turnaround report: headline KPIs plus the breakdown table for the\nrequested grouping. The common report response shape - summary, rows, generatedAt."
      },
      "ServiceDeliveryRowDto": {
        "type": "object",
        "properties": {
          "groupCode": {
            "type": "string",
            "description": "Entity code (service/client/user/team code, or \"yyyy-MM\" for months).\nNull for the null buckets (\"No service\", \"No client\", \"Unassigned\").",
            "nullable": true
          },
          "groupKind": {
            "$ref": "#/components/schemas/ReportGroupKind"
          },
          "groupName": {
            "type": "string",
            "description": "Display name for the group.",
            "nullable": true
          },
          "completedCount": {
            "type": "integer",
            "description": "Number of tasks completed in the window for this group.",
            "format": "int32"
          },
          "avgTurnaroundDays": {
            "type": "number",
            "description": "Average calendar days from planned start date to completion (negatives clamped to 0).",
            "format": "double"
          },
          "medianTurnaroundDays": {
            "type": "number",
            "description": "Median calendar days from planned start date to completion.",
            "format": "double"
          },
          "onTimePct": {
            "type": "number",
            "description": "Percentage of the group completed on or before its due date.",
            "format": "double"
          },
          "statutoryOnTimePct": {
            "type": "number",
            "description": "Percentage of the group's statutory sub-cohort completed on or before the statutory date.\nNull when no task in the group has a statutory deadline.",
            "format": "double",
            "nullable": true
          },
          "statutoryCount": {
            "type": "integer",
            "description": "Number of tasks in the group with a statutory due date - the denominator behind StatutoryOnTimePct.",
            "format": "int32"
          },
          "worstCaseDays": {
            "type": "integer",
            "description": "The slowest turnaround in the group, in days.",
            "format": "int32"
          },
          "worstTask": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          }
        },
        "additionalProperties": false,
        "description": "One row of the Service Delivery Turnaround breakdown table - the cohort aggregated for a\nsingle group (service, client, assignee, or completion month). Carries entity codes so the\nfrontend can deep-link into the filtered task list."
      },
      "ServiceDeliveryRowDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ServiceDeliveryRowDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "ServiceDeliveryStepsDto": {
        "type": "object",
        "properties": {
          "service": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "taskCount": {
            "type": "integer",
            "description": "Number of distinct workflow tasks in the cohort the step durations were derived from.",
            "format": "int32"
          },
          "totalAvgDays": {
            "type": "number",
            "description": "Average total step-covered days per task (client-wait + internal).",
            "format": "double"
          },
          "clientWaitAvgDays": {
            "type": "number",
            "description": "Average days per task spent in client-wait steps (waiting on the client to act).",
            "format": "double"
          },
          "internalAvgDays": {
            "type": "number",
            "description": "Average days per task spent in internal steps (practice-side time).",
            "format": "double"
          },
          "steps": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StepBottleneckDto"
            },
            "description": "Per-step aggregates, in workflow order.",
            "nullable": true
          },
          "generatedAt": {
            "type": "string",
            "description": "UTC timestamp the drill-down was computed.",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "Step-level bottleneck drill-down for one billable service: per-step duration aggregates\nplus the client-wait vs internal split (\"is it us or the client\")."
      },
      "ServiceDeliverySummaryDto": {
        "type": "object",
        "properties": {
          "completedCount": {
            "type": "integer",
            "description": "Number of tasks completed in the window.",
            "format": "int32"
          },
          "avgTurnaroundDays": {
            "type": "number",
            "description": "Average calendar days from planned start date to completion (negatives clamped to 0).\nNull when the cohort is empty.",
            "format": "double",
            "nullable": true
          },
          "medianTurnaroundDays": {
            "type": "number",
            "description": "Median calendar days from planned start date to completion. Null when the cohort is empty.",
            "format": "double",
            "nullable": true
          },
          "onTimePct": {
            "type": "number",
            "description": "Percentage of the cohort completed on or before its due date. Null when the cohort is empty.",
            "format": "double",
            "nullable": true
          },
          "statutoryOnTimePct": {
            "type": "number",
            "description": "Percentage of the statutory sub-cohort (tasks with a statutory due date) completed on or\nbefore that date. Null when no task in the cohort has a statutory deadline.",
            "format": "double",
            "nullable": true
          },
          "statutoryCount": {
            "type": "integer",
            "description": "Size of the statutory sub-cohort - the denominator behind StatutoryOnTimePct.",
            "format": "int32"
          },
          "overdueCount": {
            "type": "integer",
            "description": "Open tasks (NotStarted/InProgress/Blocked) past their due date right now.\nA now-snapshot: respects the entity filters but ignores the date window.",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Headline KPIs for the Service Delivery Turnaround report, computed over the completion\ncohort (tasks whose CompletedDate falls in the requested window)."
      },
      "ServiceImportJobDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique code identifying this import job.\nUse this code to poll for status via GET /{code}.",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/ImportJobStatus"
          },
          "fileName": {
            "type": "string",
            "description": "Original filename of the uploaded CSV file",
            "nullable": true
          },
          "totalItems": {
            "type": "integer",
            "description": "Total number of data rows to process (excluding header row).\nMay be null if the job hasn't started processing yet.",
            "format": "int32",
            "nullable": true
          },
          "processedItems": {
            "type": "integer",
            "description": "Number of rows that have been processed so far",
            "format": "int32"
          },
          "createdCount": {
            "type": "integer",
            "description": "Number of client billable service records created",
            "format": "int32"
          },
          "skippedCount": {
            "type": "integer",
            "description": "Number of rows skipped (client not found, service already assigned, etc.)",
            "format": "int32"
          },
          "errorCount": {
            "type": "integer",
            "description": "Number of rows with errors",
            "format": "int32"
          },
          "startedDate": {
            "type": "string",
            "description": "When the job started processing (UTC)",
            "format": "date-time",
            "nullable": true
          },
          "completedDate": {
            "type": "string",
            "description": "When the job completed processing (UTC)",
            "format": "date-time",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "When the import job was created (UTC)",
            "format": "date-time"
          },
          "notImportedDownloadUrl": {
            "type": "string",
            "description": "URL to download a CSV containing rows that were not imported.\nOnly available when status is Completed and there were errors or skipped rows.\nThis is a time-limited SAS URL that expires after 60 minutes.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Represents the current status and progress of a service import job.\nReturned when starting an import or polling for status."
      },
      "ServiceImportPreviewActionDto": {
        "type": "object",
        "properties": {
          "service": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "action": {
            "type": "string",
            "description": "What will happen: Create, Update, or Unchanged",
            "nullable": true
          },
          "price": {
            "type": "number",
            "description": "Price from the CSV. Null when the row has no price (the assignment is imported unpriced).",
            "format": "double",
            "nullable": true
          },
          "frequency": {
            "type": "string",
            "description": "Billing frequency from the CSV",
            "nullable": true
          },
          "startDate": {
            "type": "string",
            "description": "Start date from the CSV",
            "nullable": true
          },
          "endDate": {
            "type": "string",
            "description": "End date from the CSV",
            "nullable": true
          },
          "currentPrice": {
            "type": "number",
            "description": "Current price of the existing assignment (null for creates)",
            "format": "double",
            "nullable": true
          },
          "currentFrequency": {
            "type": "string",
            "description": "Current frequency of the existing assignment (null for creates)",
            "nullable": true
          },
          "currentStartDate": {
            "type": "string",
            "description": "Current start date of the existing assignment (null for creates)",
            "nullable": true
          },
          "currentEndDate": {
            "type": "string",
            "description": "Current end date of the existing assignment (null for creates)",
            "nullable": true
          },
          "autoInvoice": {
            "type": "boolean",
            "description": "AutoInvoice value from the CSV (null if column absent)",
            "nullable": true
          },
          "nextBillingDate": {
            "type": "string",
            "description": "Next billing date from the CSV (null if blank)",
            "nullable": true
          },
          "currentAutoInvoice": {
            "type": "boolean",
            "description": "Current AutoInvoice of the existing assignment (null for creates)",
            "nullable": true
          },
          "currentNextBillingDate": {
            "type": "string",
            "description": "Current next billing date of the existing assignment (null for creates)",
            "nullable": true
          },
          "stage": {
            "type": "string",
            "description": "Service stage name from the CSV (null if column blank)",
            "nullable": true
          },
          "currentStage": {
            "type": "string",
            "description": "Current service stage name of the existing assignment (null for creates)",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Preview for a single service action within a client"
      },
      "ServiceImportPreviewClientDto": {
        "type": "object",
        "properties": {
          "client": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "csvClientName": {
            "type": "string",
            "description": "The client name as it appears in the CSV (used when client is not found)",
            "nullable": true
          },
          "error": {
            "type": "string",
            "description": "Error message if client could not be matched",
            "nullable": true
          },
          "services": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ServiceImportPreviewActionDto"
            },
            "description": "Services that will be created, updated, or skipped for this client",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Preview for a single client row in the CSV"
      },
      "ServiceImportPreviewDto": {
        "type": "object",
        "properties": {
          "asyncJobCode": {
            "type": "string",
            "description": "Job code to pass to the confirm endpoint to execute the import",
            "nullable": true
          },
          "fileName": {
            "type": "string",
            "description": "Original filename",
            "nullable": true
          },
          "clients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ServiceImportPreviewClientDto"
            },
            "description": "Per-client breakdown of what will happen",
            "nullable": true
          },
          "totalClients": {
            "type": "integer",
            "description": "Total number of client rows in the CSV",
            "format": "int32"
          },
          "clientsFound": {
            "type": "integer",
            "description": "Number of clients matched to existing clients",
            "format": "int32"
          },
          "clientsNotFound": {
            "type": "integer",
            "description": "Number of client rows where no matching client was found",
            "format": "int32"
          },
          "servicesToCreate": {
            "type": "integer",
            "description": "Number of new service assignments that will be created",
            "format": "int32"
          },
          "servicesToUpdate": {
            "type": "integer",
            "description": "Number of existing service assignments that will be updated (values differ)",
            "format": "int32"
          },
          "servicesUnchanged": {
            "type": "integer",
            "description": "Number of existing service assignments that are unchanged and will be skipped",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Preview of what a service CSV import will do, returned before the user confirms."
      },
      "ServicePackageDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this service package",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The name of the service package",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Description of what this package includes",
            "nullable": true
          },
          "isArchived": {
            "type": "boolean",
            "description": "Whether this package is archived (inactive)"
          },
          "usePackagePricing": {
            "type": "boolean",
            "description": "Whether this package uses a single package-level price instead of summing individual item prices"
          },
          "packagePrice": {
            "type": "number",
            "description": "The flat price for the entire package. Only present when UsePackagePricing is true.",
            "format": "double",
            "nullable": true
          },
          "packageBillingFrequency": {
            "$ref": "#/components/schemas/BillingFrequency"
          },
          "packageSetupFee": {
            "type": "number",
            "description": "Optional one-off setup fee for the package, billed once when the package is first invoiced.\nOnly used when UsePackagePricing is true. Null means no setup fee.",
            "format": "double",
            "nullable": true
          },
          "proposalContent": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "totalAnnualValue": {
            "type": "number",
            "description": "The total annual value of all services in this package",
            "format": "double"
          },
          "numberOfServices": {
            "type": "integer",
            "description": "The number of services in this package",
            "format": "int32"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ServicePackageItemDto"
            },
            "description": "The services included in this package",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "When the package was created",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "description": "When the package was last updated",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response DTO for service package information"
      },
      "ServicePackageDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ServicePackageDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "ServicePackageItemDto": {
        "type": "object",
        "properties": {
          "billableServiceCode": {
            "type": "string",
            "description": "The code of the billable service",
            "nullable": true
          },
          "billableServiceName": {
            "type": "string",
            "description": "The name of the billable service",
            "nullable": true
          },
          "billingFrequency": {
            "$ref": "#/components/schemas/BillingFrequency"
          },
          "overridePricing": {
            "type": "boolean",
            "description": "Whether to override the standard pricing from the billable service"
          },
          "price": {
            "type": "number",
            "description": "The custom price to use when OverridePricing is true",
            "format": "double",
            "nullable": true
          },
          "pricingAnswers": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Pre-answered pricing factors (key = factor description, value = selected option name)",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "DTO for a service included in a service package"
      },
      "ServicePackageSortField": {
        "enum": [
          "Name"
        ],
        "type": "string"
      },
      "ServicePricingMode": {
        "enum": [
          "RevenueRange",
          "CustomTiers"
        ],
        "type": "string"
      },
      "ServiceStatus": {
        "enum": [
          "Active",
          "Inactive",
          "Paused",
          "Proposed"
        ],
        "type": "string"
      },
      "ServiceTimeReportDto": {
        "type": "object",
        "properties": {
          "summary": {
            "$ref": "#/components/schemas/ServiceTimeSummaryDto"
          },
          "rows": {
            "$ref": "#/components/schemas/ServiceTimeRowDtoPagedResult"
          },
          "generatedAt": {
            "type": "string",
            "description": "When the report was generated (UTC)",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "The Service Time report: estimated vs actual time per service (\"we sold this for X hours —\ndid it take X?\"), computed from time entries attributed to services via their linked tasks.\nWhen a service drill-down is requested, rows are per client instead of per service."
      },
      "ServiceTimeRowDto": {
        "type": "object",
        "properties": {
          "groupCode": {
            "type": "string",
            "description": "The code of the group — a service code, or a client code in the drill-down",
            "nullable": true
          },
          "groupName": {
            "type": "string",
            "description": "The display name of the group",
            "nullable": true
          },
          "estimatedMinutes": {
            "type": "integer",
            "description": "Summed effective estimates of the tasks the time was logged against — per task the\nsum of its non-omitted workflow step estimates, falling back to the task's own\nestimate when it has no step estimates. Null when no task has an estimate.",
            "format": "int32",
            "nullable": true
          },
          "totalMinutes": {
            "type": "integer",
            "description": "Total minutes logged against the group in the window",
            "format": "int32"
          },
          "entryCount": {
            "type": "integer",
            "description": "Number of time entries behind the total",
            "format": "int32"
          },
          "engagementCount": {
            "type": "integer",
            "description": "Number of distinct client-service engagements the time was logged against",
            "format": "int32"
          },
          "taskCount": {
            "type": "integer",
            "description": "Number of distinct tasks the time was logged against (the estimate is summed over these)",
            "format": "int32"
          },
          "varianceMinutes": {
            "type": "number",
            "description": "Total minutes minus the estimate — positive means over estimate.\nNull when no task behind the row has an estimate.",
            "format": "double",
            "nullable": true
          },
          "variancePct": {
            "type": "number",
            "description": "Variance as a percentage of the estimate — positive means over estimate.\nNull when no task behind the row has an estimate.",
            "format": "double",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One Service Time breakdown row"
      },
      "ServiceTimeRowDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ServiceTimeRowDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "ServiceTimeSummaryDto": {
        "type": "object",
        "properties": {
          "totalMinutes": {
            "type": "integer",
            "description": "Total minutes logged in the window",
            "format": "int32"
          },
          "attributedMinutes": {
            "type": "integer",
            "description": "Minutes attributable to a service (entry linked to a task that carries a service)",
            "format": "int32"
          },
          "unattributedMinutes": {
            "type": "integer",
            "description": "Minutes not attributable to any service — included so the breakdown reconciles with the total",
            "format": "int32"
          },
          "billableMinutes": {
            "type": "integer",
            "description": "Minutes marked billable in the window",
            "format": "int32"
          },
          "entryCount": {
            "type": "integer",
            "description": "Number of time entries in the window",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Headline aggregates for the Service Time report"
      },
      "SetOrganizationRequest": {
        "type": "object",
        "properties": {
          "organizationId": {
            "type": "string",
            "description": "The organization ID to set",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request to set organization for a third-party connection"
      },
      "SetPipelineStageStepConfigDto": {
        "type": "object",
        "properties": {
          "pipelineCode": {
            "type": "string",
            "description": "The code of the Pipeline whose stage should be set",
            "nullable": true
          },
          "stageCode": {
            "type": "string",
            "description": "The code of the PipelineStage to set on the client's pipeline card",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Configuration for SetPipelineStage workflow steps.\nSets the stage on the client's pipeline card when executed."
      },
      "SetPortalAccessRequest": {
        "type": "object",
        "properties": {
          "hasPortalAccess": {
            "type": "boolean",
            "description": "Whether the contact should have portal access."
          }
        },
        "additionalProperties": false,
        "description": "Request to grant or revoke portal access for a contact."
      },
      "SetSavedFilterMenuRequest": {
        "type": "object",
        "properties": {
          "includeInMenu": {
            "type": "boolean",
            "description": "Whether the filter should appear in the current user's menu/quick access list"
          }
        },
        "additionalProperties": false,
        "description": "Request to set the current user's menu preference for a saved filter"
      },
      "SetServiceStageStepConfigDto": {
        "type": "object",
        "properties": {
          "billableServiceCode": {
            "type": "string",
            "description": "The code of the BillableService whose stage should be set",
            "nullable": true
          },
          "stageCode": {
            "type": "string",
            "description": "The code of the BillableServiceStage to set on the client's service",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Configuration for SetServiceStage workflow steps.\nSets the stage on the client's billable service when executed."
      },
      "SicCode": {
        "enum": [
          "SIC01110",
          "SIC01120",
          "SIC01130",
          "SIC01140",
          "SIC01150",
          "SIC01160",
          "SIC01190",
          "SIC01210",
          "SIC01220",
          "SIC01230",
          "SIC01240",
          "SIC01250",
          "SIC01260",
          "SIC01270",
          "SIC01280",
          "SIC01290",
          "SIC01300",
          "SIC01410",
          "SIC01420",
          "SIC01430",
          "SIC01440",
          "SIC01450",
          "SIC01460",
          "SIC01470",
          "SIC01490",
          "SIC01500",
          "SIC01610",
          "SIC01621",
          "SIC01629",
          "SIC01630",
          "SIC01640",
          "SIC01700",
          "SIC02100",
          "SIC02200",
          "SIC02300",
          "SIC02400",
          "SIC03110",
          "SIC03120",
          "SIC03210",
          "SIC03220",
          "SIC05101",
          "SIC05102",
          "SIC05200",
          "SIC06100",
          "SIC06200",
          "SIC07100",
          "SIC07210",
          "SIC07290",
          "SIC08110",
          "SIC08120",
          "SIC08910",
          "SIC08920",
          "SIC08930",
          "SIC08990",
          "SIC09100",
          "SIC09900",
          "SIC10110",
          "SIC10120",
          "SIC10130",
          "SIC10200",
          "SIC10310",
          "SIC10320",
          "SIC10390",
          "SIC10410",
          "SIC10420",
          "SIC10511",
          "SIC10512",
          "SIC10519",
          "SIC10520",
          "SIC10611",
          "SIC10612",
          "SIC10620",
          "SIC10710",
          "SIC10720",
          "SIC10730",
          "SIC10810",
          "SIC10821",
          "SIC10822",
          "SIC10831",
          "SIC10832",
          "SIC10840",
          "SIC10850",
          "SIC10860",
          "SIC10890",
          "SIC10910",
          "SIC10920",
          "SIC11010",
          "SIC11020",
          "SIC11030",
          "SIC11040",
          "SIC11050",
          "SIC11060",
          "SIC11070",
          "SIC12000",
          "SIC13100",
          "SIC13200",
          "SIC13300",
          "SIC13910",
          "SIC13921",
          "SIC13922",
          "SIC13923",
          "SIC13931",
          "SIC13939",
          "SIC13940",
          "SIC13950",
          "SIC13960",
          "SIC13990",
          "SIC14110",
          "SIC14120",
          "SIC14131",
          "SIC14132",
          "SIC14141",
          "SIC14142",
          "SIC14190",
          "SIC14200",
          "SIC14310",
          "SIC14390",
          "SIC15110",
          "SIC15120",
          "SIC15200",
          "SIC16100",
          "SIC16210",
          "SIC16220",
          "SIC16230",
          "SIC16240",
          "SIC16290",
          "SIC17110",
          "SIC17120",
          "SIC17211",
          "SIC17219",
          "SIC17220",
          "SIC17230",
          "SIC17240",
          "SIC17290",
          "SIC18110",
          "SIC18121",
          "SIC18129",
          "SIC18130",
          "SIC18140",
          "SIC18201",
          "SIC18202",
          "SIC18203",
          "SIC19100",
          "SIC19201",
          "SIC19209",
          "SIC20110",
          "SIC20120",
          "SIC20130",
          "SIC20140",
          "SIC20150",
          "SIC20160",
          "SIC20170",
          "SIC20200",
          "SIC20301",
          "SIC20302",
          "SIC20411",
          "SIC20412",
          "SIC20420",
          "SIC20510",
          "SIC20520",
          "SIC20530",
          "SIC20590",
          "SIC20600",
          "SIC21100",
          "SIC21200",
          "SIC22110",
          "SIC22190",
          "SIC22210",
          "SIC22220",
          "SIC22230",
          "SIC22290",
          "SIC23110",
          "SIC23120",
          "SIC23130",
          "SIC23140",
          "SIC23190",
          "SIC23200",
          "SIC23310",
          "SIC23320",
          "SIC23410",
          "SIC23420",
          "SIC23430",
          "SIC23440",
          "SIC23490",
          "SIC23510",
          "SIC23520",
          "SIC23610",
          "SIC23620",
          "SIC23630",
          "SIC23640",
          "SIC23650",
          "SIC23690",
          "SIC23700",
          "SIC23910",
          "SIC23990",
          "SIC24100",
          "SIC24200",
          "SIC24310",
          "SIC24320",
          "SIC24330",
          "SIC24340",
          "SIC24410",
          "SIC24420",
          "SIC24430",
          "SIC24440",
          "SIC24450",
          "SIC24460",
          "SIC24510",
          "SIC24520",
          "SIC24530",
          "SIC24540",
          "SIC25110",
          "SIC25120",
          "SIC25210",
          "SIC25290",
          "SIC25300",
          "SIC25400",
          "SIC25500",
          "SIC25610",
          "SIC25620",
          "SIC25710",
          "SIC25720",
          "SIC25730",
          "SIC25910",
          "SIC25920",
          "SIC25930",
          "SIC25940",
          "SIC25990",
          "SIC26110",
          "SIC26120",
          "SIC26200",
          "SIC26301",
          "SIC26309",
          "SIC26400",
          "SIC26511",
          "SIC26512",
          "SIC26513",
          "SIC26514",
          "SIC26520",
          "SIC26600",
          "SIC26701",
          "SIC26702",
          "SIC26800",
          "SIC27110",
          "SIC27120",
          "SIC27200",
          "SIC27310",
          "SIC27320",
          "SIC27330",
          "SIC27400",
          "SIC27510",
          "SIC27520",
          "SIC27900",
          "SIC28110",
          "SIC28120",
          "SIC28131",
          "SIC28132",
          "SIC28140",
          "SIC28150",
          "SIC28210",
          "SIC28220",
          "SIC28230",
          "SIC28240",
          "SIC28250",
          "SIC28290",
          "SIC28301",
          "SIC28302",
          "SIC28410",
          "SIC28490",
          "SIC28910",
          "SIC28921",
          "SIC28922",
          "SIC28923",
          "SIC28930",
          "SIC28940",
          "SIC28950",
          "SIC28960",
          "SIC28990",
          "SIC29100",
          "SIC29201",
          "SIC29202",
          "SIC29203",
          "SIC29310",
          "SIC29320",
          "SIC30110",
          "SIC30120",
          "SIC30200",
          "SIC30300",
          "SIC30400",
          "SIC30910",
          "SIC30920",
          "SIC30990",
          "SIC31010",
          "SIC31020",
          "SIC31030",
          "SIC31090",
          "SIC32110",
          "SIC32120",
          "SIC32130",
          "SIC32200",
          "SIC32300",
          "SIC32401",
          "SIC32409",
          "SIC32500",
          "SIC32910",
          "SIC32990",
          "SIC33110",
          "SIC33120",
          "SIC33130",
          "SIC33140",
          "SIC33150",
          "SIC33160",
          "SIC33170",
          "SIC33190",
          "SIC33200",
          "SIC35110",
          "SIC35120",
          "SIC35130",
          "SIC35140",
          "SIC35210",
          "SIC35220",
          "SIC35230",
          "SIC35300",
          "SIC36000",
          "SIC37000",
          "SIC38110",
          "SIC38120",
          "SIC38210",
          "SIC38220",
          "SIC38310",
          "SIC38320",
          "SIC39000",
          "SIC41100",
          "SIC41201",
          "SIC41202",
          "SIC42110",
          "SIC42120",
          "SIC42130",
          "SIC42210",
          "SIC42220",
          "SIC42910",
          "SIC42990",
          "SIC43110",
          "SIC43120",
          "SIC43130",
          "SIC43210",
          "SIC43220",
          "SIC43290",
          "SIC43310",
          "SIC43320",
          "SIC43330",
          "SIC43341",
          "SIC43342",
          "SIC43390",
          "SIC43910",
          "SIC43991",
          "SIC43999",
          "SIC45111",
          "SIC45112",
          "SIC45190",
          "SIC45200",
          "SIC45310",
          "SIC45320",
          "SIC45400",
          "SIC46110",
          "SIC46120",
          "SIC46130",
          "SIC46140",
          "SIC46150",
          "SIC46160",
          "SIC46170",
          "SIC46180",
          "SIC46190",
          "SIC46210",
          "SIC46220",
          "SIC46230",
          "SIC46240",
          "SIC46310",
          "SIC46320",
          "SIC46330",
          "SIC46341",
          "SIC46342",
          "SIC46350",
          "SIC46360",
          "SIC46370",
          "SIC46380",
          "SIC46390",
          "SIC46410",
          "SIC46420",
          "SIC46431",
          "SIC46439",
          "SIC46440",
          "SIC46450",
          "SIC46460",
          "SIC46470",
          "SIC46480",
          "SIC46491",
          "SIC46499",
          "SIC46510",
          "SIC46520",
          "SIC46610",
          "SIC46620",
          "SIC46630",
          "SIC46640",
          "SIC46650",
          "SIC46660",
          "SIC46690",
          "SIC46711",
          "SIC46719",
          "SIC46720",
          "SIC46730",
          "SIC46740",
          "SIC46750",
          "SIC46760",
          "SIC46770",
          "SIC46900",
          "SIC47110",
          "SIC47190",
          "SIC47210",
          "SIC47220",
          "SIC47230",
          "SIC47240",
          "SIC47250",
          "SIC47260",
          "SIC47290",
          "SIC47300",
          "SIC47410",
          "SIC47421",
          "SIC47429",
          "SIC47430",
          "SIC47510",
          "SIC47520",
          "SIC47530",
          "SIC47540",
          "SIC47591",
          "SIC47599",
          "SIC47610",
          "SIC47620",
          "SIC47630",
          "SIC47640",
          "SIC47650",
          "SIC47710",
          "SIC47721",
          "SIC47722",
          "SIC47730",
          "SIC47741",
          "SIC47749",
          "SIC47750",
          "SIC47760",
          "SIC47770",
          "SIC47781",
          "SIC47782",
          "SIC47789",
          "SIC47791",
          "SIC47799",
          "SIC47810",
          "SIC47820",
          "SIC47890",
          "SIC47910",
          "SIC47990",
          "SIC49100",
          "SIC49200",
          "SIC49311",
          "SIC49319",
          "SIC49320",
          "SIC49390",
          "SIC49410",
          "SIC49420",
          "SIC49500",
          "SIC50100",
          "SIC50200",
          "SIC50300",
          "SIC50400",
          "SIC51101",
          "SIC51102",
          "SIC51210",
          "SIC51220",
          "SIC52101",
          "SIC52102",
          "SIC52103",
          "SIC52109",
          "SIC52211",
          "SIC52212",
          "SIC52213",
          "SIC52219",
          "SIC52220",
          "SIC52230",
          "SIC52241",
          "SIC52242",
          "SIC52243",
          "SIC52290",
          "SIC53100",
          "SIC53201",
          "SIC53202",
          "SIC55100",
          "SIC55201",
          "SIC55202",
          "SIC55209",
          "SIC55300",
          "SIC55900",
          "SIC56101",
          "SIC56102",
          "SIC56103",
          "SIC56210",
          "SIC56290",
          "SIC56301",
          "SIC56302",
          "SIC58110",
          "SIC58120",
          "SIC58130",
          "SIC58141",
          "SIC58142",
          "SIC58190",
          "SIC58210",
          "SIC58290",
          "SIC59111",
          "SIC59112",
          "SIC59113",
          "SIC59120",
          "SIC59131",
          "SIC59132",
          "SIC59133",
          "SIC59140",
          "SIC59200",
          "SIC60100",
          "SIC60200",
          "SIC61100",
          "SIC61200",
          "SIC61300",
          "SIC61900",
          "SIC62011",
          "SIC62012",
          "SIC62020",
          "SIC62030",
          "SIC62090",
          "SIC63110",
          "SIC63120",
          "SIC63910",
          "SIC63990",
          "SIC64110",
          "SIC64191",
          "SIC64192",
          "SIC64201",
          "SIC64202",
          "SIC64203",
          "SIC64204",
          "SIC64205",
          "SIC64209",
          "SIC64301",
          "SIC64302",
          "SIC64303",
          "SIC64304",
          "SIC64305",
          "SIC64306",
          "SIC64910",
          "SIC64921",
          "SIC64922",
          "SIC64929",
          "SIC64991",
          "SIC64992",
          "SIC64999",
          "SIC65110",
          "SIC65120",
          "SIC65201",
          "SIC65202",
          "SIC65300",
          "SIC66110",
          "SIC66120",
          "SIC66190",
          "SIC66210",
          "SIC66220",
          "SIC66290",
          "SIC66300",
          "SIC68100",
          "SIC68201",
          "SIC68202",
          "SIC68209",
          "SIC68310",
          "SIC68320",
          "SIC69101",
          "SIC69102",
          "SIC69109",
          "SIC69201",
          "SIC69202",
          "SIC69203",
          "SIC70100",
          "SIC70210",
          "SIC70221",
          "SIC70229",
          "SIC71111",
          "SIC71112",
          "SIC71121",
          "SIC71122",
          "SIC71129",
          "SIC71200",
          "SIC72110",
          "SIC72190",
          "SIC72200",
          "SIC73110",
          "SIC73120",
          "SIC73200",
          "SIC74100",
          "SIC74201",
          "SIC74202",
          "SIC74203",
          "SIC74209",
          "SIC74300",
          "SIC74901",
          "SIC74902",
          "SIC74909",
          "SIC75000",
          "SIC77110",
          "SIC77120",
          "SIC77210",
          "SIC77220",
          "SIC77291",
          "SIC77299",
          "SIC77310",
          "SIC77320",
          "SIC77330",
          "SIC77341",
          "SIC77342",
          "SIC77351",
          "SIC77352",
          "SIC77390",
          "SIC77400",
          "SIC78101",
          "SIC78109",
          "SIC78200",
          "SIC78300",
          "SIC79110",
          "SIC79120",
          "SIC79901",
          "SIC79909",
          "SIC80100",
          "SIC80200",
          "SIC80300",
          "SIC81100",
          "SIC81210",
          "SIC81221",
          "SIC81222",
          "SIC81223",
          "SIC81229",
          "SIC81291",
          "SIC81299",
          "SIC81300",
          "SIC82110",
          "SIC82190",
          "SIC82200",
          "SIC82301",
          "SIC82302",
          "SIC82911",
          "SIC82912",
          "SIC82920",
          "SIC82990",
          "SIC84110",
          "SIC84120",
          "SIC84130",
          "SIC84210",
          "SIC84220",
          "SIC84230",
          "SIC84240",
          "SIC84250",
          "SIC84300",
          "SIC85100",
          "SIC85200",
          "SIC85310",
          "SIC85320",
          "SIC85410",
          "SIC85421",
          "SIC85422",
          "SIC85510",
          "SIC85520",
          "SIC85530",
          "SIC85590",
          "SIC85600",
          "SIC86101",
          "SIC86102",
          "SIC86210",
          "SIC86220",
          "SIC86230",
          "SIC86900",
          "SIC87100",
          "SIC87200",
          "SIC87300",
          "SIC87900",
          "SIC88100",
          "SIC88910",
          "SIC88990",
          "SIC90010",
          "SIC90020",
          "SIC90030",
          "SIC90040",
          "SIC91011",
          "SIC91012",
          "SIC91020",
          "SIC91030",
          "SIC91040",
          "SIC92000",
          "SIC93110",
          "SIC93120",
          "SIC93130",
          "SIC93191",
          "SIC93199",
          "SIC93210",
          "SIC93290",
          "SIC94110",
          "SIC94120",
          "SIC94200",
          "SIC94910",
          "SIC94920",
          "SIC94990",
          "SIC95110",
          "SIC95120",
          "SIC95210",
          "SIC95220",
          "SIC95230",
          "SIC95240",
          "SIC95250",
          "SIC95290",
          "SIC96010",
          "SIC96020",
          "SIC96030",
          "SIC96040",
          "SIC96090",
          "SIC97000",
          "SIC98000",
          "SIC98100",
          "SIC98200",
          "SIC99000",
          "SIC99999"
        ],
        "type": "string"
      },
      "SmtpEncryption": {
        "enum": [
          "Auto",
          "Ssl",
          "Tls"
        ],
        "type": "string",
        "description": "SMTP encryption methods"
      },
      "SmtpSettingsRequest": {
        "required": [
          "host",
          "port"
        ],
        "type": "object",
        "properties": {
          "host": {
            "minLength": 1,
            "type": "string",
            "description": "SMTP server host"
          },
          "port": {
            "type": "integer",
            "description": "SMTP server port",
            "format": "int32"
          },
          "encryption": {
            "$ref": "#/components/schemas/SmtpEncryption"
          },
          "requiresAuthentication": {
            "type": "boolean",
            "description": "Indicates whether the SMTP server requires authentication\nIf false, the connection will be made without authentication (open relay)"
          },
          "username": {
            "type": "string",
            "description": "SMTP username (required if RequiresAuthentication = true)",
            "nullable": true
          },
          "password": {
            "type": "string",
            "description": "SMTP password (required if RequiresAuthentication = true)",
            "nullable": true
          },
          "timeout": {
            "type": "integer",
            "description": "Connection timeout in milliseconds",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "SMTP settings for API requests"
      },
      "SmtpSettingsResponseDto": {
        "type": "object",
        "properties": {
          "host": {
            "type": "string",
            "description": "SMTP server host",
            "nullable": true
          },
          "port": {
            "type": "integer",
            "description": "SMTP server port",
            "format": "int32"
          },
          "encryption": {
            "$ref": "#/components/schemas/SmtpEncryption"
          },
          "requiresAuthentication": {
            "type": "boolean",
            "description": "Indicates whether the SMTP server requires authentication"
          },
          "username": {
            "type": "string",
            "description": "SMTP username",
            "nullable": true
          },
          "hasPassword": {
            "type": "boolean",
            "description": "Whether a password is configured (true/false, actual password never returned)"
          },
          "timeout": {
            "type": "integer",
            "description": "Connection timeout in milliseconds",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "SMTP settings response (passwords are never returned)"
      },
      "StartDateType": {
        "enum": [
          "SpecificDate",
          "WeekDay",
          "MonthDay",
          "ClientDate",
          "RelativeToDue"
        ],
        "type": "string"
      },
      "StartRunningTimerRequest": {
        "type": "object",
        "properties": {
          "description": {
            "maxLength": 1000,
            "type": "string",
            "description": "What the time is being spent on",
            "nullable": true
          },
          "isBillable": {
            "type": "boolean",
            "description": "Whether the logged time will be billable — carried onto the entry when the timer stops"
          },
          "clientCode": {
            "type": "string",
            "description": "The code of the client the time relates to (optional)",
            "nullable": true
          },
          "taskItemCode": {
            "type": "string",
            "description": "The code of the task the time relates to (optional)",
            "nullable": true
          },
          "workflowGroupNumber": {
            "type": "integer",
            "description": "The group number of the workflow step the time relates to (optional; requires\nTaskItemCode and WorkflowStepNumber) — carried onto the entry when the timer stops",
            "format": "int32",
            "nullable": true
          },
          "workflowStepNumber": {
            "type": "integer",
            "description": "The step number of the workflow step the time relates to (optional; requires\nTaskItemCode and WorkflowGroupNumber) — carried onto the entry when the timer stops",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request to start the calling user's timer, or update the details of the one\nalready running (the start time is preserved on update)"
      },
      "StartSubscriptionBillingRequest": {
        "type": "object",
        "properties": {
          "billingAddress": {
            "$ref": "#/components/schemas/BillingAddress"
          }
        },
        "additionalProperties": false,
        "description": "Request to start subscription billing for a tenant.\nName, billing contact, and tenant are auto-populated from context."
      },
      "StatutoryDateConfigDto": {
        "type": "object",
        "properties": {
          "type": {
            "$ref": "#/components/schemas/StatutoryDateType"
          },
          "fixedMonth": {
            "type": "integer",
            "description": "Month (1-12). Required when Type is SpecificDate.",
            "format": "int32",
            "nullable": true
          },
          "fixedDay": {
            "type": "integer",
            "description": "Day of month (1-31). Required when Type is SpecificDate. Clamped to last day of month at projection time.",
            "format": "int32",
            "nullable": true
          },
          "dayOfMonth": {
            "type": "integer",
            "description": "Nth day of month (1-31). Required when Type is DayOfMonth. Clamped to last day for shorter months.",
            "format": "int32",
            "nullable": true
          },
          "clientDateSourceType": {
            "$ref": "#/components/schemas/ClientDateSourceType"
          },
          "clientDateType": {
            "$ref": "#/components/schemas/ClientDateType"
          },
          "customFieldDefinitionCode": {
            "type": "string",
            "description": "Custom field code. Required when Type is ClientKeyDate and ClientDateSourceType is CustomField.",
            "nullable": true
          },
          "customFieldDefinitionLabel": {
            "type": "string",
            "description": "Custom field label. Populated in responses only.",
            "nullable": true
          },
          "timing": {
            "$ref": "#/components/schemas/DaysBeforeOrAfter"
          },
          "offsetDays": {
            "type": "integer",
            "description": "Days portion of the offset relative to the client date. Required when Type is ClientKeyDate.",
            "format": "int32",
            "nullable": true
          },
          "offsetMonths": {
            "type": "integer",
            "description": "Months portion of the offset relative to the client date. Optional alongside OffsetDays - e.g.\n\"Year End + 9 months + 1 day\" for CT payment. Must be >= 0 when set; direction comes from Timing.",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Configuration for the projected StatutoryDueDate on tasks created from a recurring task.\nDifferent properties are required based on the Type value:\n- None: no statutory date is set.\n- SpecificDate: FixedMonth + FixedDay (DD/MM annual; invalid days clamped to end-of-month).\n- ClientKeyDate: ClientDateSourceType + Timing + OffsetDays (OffsetMonths optional), plus\n  ClientDateType (KeyDate source) or CustomFieldDefinitionCode (CustomField source).\n- DayOfMonth: DayOfMonth (1-31; clamped to last day for shorter months)."
      },
      "StatutoryDateType": {
        "enum": [
          "None",
          "SpecificDate",
          "ClientKeyDate",
          "DayOfMonth"
        ],
        "type": "string"
      },
      "StepBottleneckDto": {
        "type": "object",
        "properties": {
          "groupName": {
            "type": "string",
            "description": "The workflow group (section) the step belongs to - lets the UI divide the step table\ninto the same sections the workflow shows.",
            "nullable": true
          },
          "stepName": {
            "type": "string",
            "description": "Step name (snapshotted per task; renamed steps aggregate separately).",
            "nullable": true
          },
          "stepType": {
            "$ref": "#/components/schemas/WorkflowStepType"
          },
          "stage": {
            "$ref": "#/components/schemas/ClientBillableServiceStageDto"
          },
          "isClientWait": {
            "type": "boolean",
            "description": "True when the step completes on a client action - its elapsed time is client-wait time\n(DocumentRequest, DocumentApproval, ClientConfirmation, SendDataForm). False = internal time."
          },
          "count": {
            "type": "integer",
            "description": "Number of step instances (completed or skipped) aggregated into this row.",
            "format": "int32"
          },
          "avgDurationDays": {
            "type": "number",
            "description": "Average elapsed days from the previous step's completion to this step's completion.",
            "format": "double"
          },
          "skippedCount": {
            "type": "integer",
            "description": "How many of the instances were skipped rather than completed. Skipped steps stay in the\naverages (their elapsed time is real time the task sat there) - this column makes that visible.",
            "format": "int32"
          },
          "avgChaseCount": {
            "type": "number",
            "description": "Average number of chases sent for this step (client-facing steps only; 0 elsewhere).",
            "format": "double"
          }
        },
        "additionalProperties": false,
        "description": "Duration aggregates for one workflow step across the cohort's workflow tasks for a single\nbillable service. A step's duration runs from the previous step's completion (or the task's\nactual start for the first step) to its own completion, so it includes idle time waiting\nfor the step to begin - the \"where do tasks sit\" measure."
      },
      "StorageLocationDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Platform-specific identifier for this group (e.g. SharePoint site ID).",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name of the group (e.g. \"Client A Site\").",
            "nullable": true
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StorageLocationItemDto"
            },
            "description": "Selectable storage locations within this group.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A group of selectable storage locations available through a connection\n(e.g. a SharePoint site containing document libraries)."
      },
      "StorageLocationItemDto": {
        "type": "object",
        "properties": {
          "driveId": {
            "type": "string",
            "description": "Platform-specific drive identifier. Pass as driveId when browsing folders or assigning client folders.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name of the storage location.",
            "nullable": true
          },
          "webUrl": {
            "type": "string",
            "description": "Direct link to the storage location in the provider's web UI.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A selectable storage location (e.g. a document library / drive) that can be assigned to a client."
      },
      "StorageType": {
        "enum": [
          "AzureBlob",
          "External"
        ],
        "type": "string"
      },
      "SubmitDocumentRequestRequest": {
        "type": "object",
        "properties": {
          "comments": {
            "type": "string",
            "description": "Comments to include with the submission. Required if no documents are attached.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for submitting a document request response"
      },
      "SubmitInvoiceRequest": {
        "required": [
          "billingDate"
        ],
        "type": "object",
        "properties": {
          "billingDate": {
            "type": "string",
            "description": "The billing date of the projected submission to create and push",
            "format": "date"
          }
        },
        "additionalProperties": false,
        "description": "Request body for submitting an invoice for a specific billing date"
      },
      "SubmitLetterAuthCodeRequest": {
        "required": [
          "authorisationCode",
          "authorisationType"
        ],
        "type": "object",
        "properties": {
          "authorisationType": {
            "$ref": "#/components/schemas/AgentAuthorisationType"
          },
          "authorisationCode": {
            "maxLength": 20,
            "minLength": 1,
            "type": "string",
            "description": "The authorisation code from the letter HMRC posted to the client"
          }
        },
        "additionalProperties": false,
        "description": "Request to submit the authorisation code received by post from HMRC (letter-based flow)."
      },
      "SubscriptionDiscountDto": {
        "type": "object",
        "properties": {
          "discountCodeValue": {
            "type": "string",
            "description": "The discount code that was redeemed.",
            "nullable": true
          },
          "discountPercent": {
            "type": "integer",
            "description": "The percentage discount being applied.",
            "format": "int32"
          },
          "startDate": {
            "type": "string",
            "description": "When the discount started.",
            "format": "date-time"
          },
          "endDate": {
            "type": "string",
            "description": "When the discount expires. Null means permanent.",
            "format": "date-time",
            "nullable": true
          },
          "hasBeenBilled": {
            "type": "boolean",
            "description": "Whether this discount has been applied to at least one billing cycle.\nIf true, the discount cannot be re-applied after removal."
          }
        },
        "additionalProperties": false,
        "description": "Response DTO for an active subscription discount on a tenant."
      },
      "SubscriptionDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this subscription",
            "nullable": true
          },
          "package": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "pricingTier": {
            "$ref": "#/components/schemas/PricingTierDto"
          },
          "monthlyPricePence": {
            "type": "integer",
            "description": "The monthly price in pence",
            "format": "int32"
          },
          "startDate": {
            "type": "string",
            "description": "When the subscription started",
            "format": "date-time"
          },
          "endDate": {
            "type": "string",
            "description": "When the subscription ends (null for perpetual subscriptions)",
            "format": "date-time",
            "nullable": true
          },
          "comment": {
            "type": "string",
            "description": "Optional comment about the subscription",
            "nullable": true
          },
          "isFreeTrial": {
            "type": "boolean",
            "description": "Whether this subscription is a free trial"
          },
          "pendingSubscription": {
            "$ref": "#/components/schemas/SubscriptionDto"
          },
          "discount": {
            "$ref": "#/components/schemas/SubscriptionDiscountDto"
          }
        },
        "additionalProperties": false,
        "description": "Response DTO for subscription information (excludes internal IDs)"
      },
      "SubscriptionPricePreviewDto": {
        "type": "object",
        "properties": {
          "package": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "pricingTier": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "monthlyPricePence": {
            "type": "integer",
            "description": "The base monthly price in pence before any discounts.",
            "format": "int32"
          },
          "discountPercent": {
            "type": "integer",
            "description": "The active discount percentage applied (0 if no discount).",
            "format": "int32"
          },
          "discountedMonthlyPricePence": {
            "type": "integer",
            "description": "The discounted monthly price in pence after applying any active discount.",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Preview of the subscription price for a package based on the tenant's active client count."
      },
      "SystemFolderType": {
        "enum": [
          "None",
          "Inbox",
          "Sent",
          "Drafts",
          "Junk",
          "Trash",
          "Archive",
          "Outbox",
          "GmailCategory",
          "GmailPromotionalCategory"
        ],
        "type": "string",
        "description": "Identifies which provider-system folder a row represents.\nNone (0, the default) means the row is a user-created folder or a Gmail user label."
      },
      "SystemRole": {
        "enum": [
          "Admin",
          "StandardUser",
          "Viewer"
        ],
        "type": "string"
      },
      "TaskCategoryDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this task category",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The display name of the task category",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "The sort order for displaying task categories",
            "format": "int32"
          },
          "color": {
            "type": "string",
            "description": "The color associated with this task category",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A grouping used to classify tasks"
      },
      "TaskCategoryDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TaskCategoryDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "TaskCategorySortField": {
        "enum": [
          "SortOrder",
          "Name"
        ],
        "type": "string"
      },
      "TaskDateBasis": {
        "enum": [
          "Any",
          "StartDate",
          "DueDate",
          "StatutoryDate",
          "CompletedDate"
        ],
        "type": "string"
      },
      "TaskFocusConfigDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique identifier within the tenant",
            "nullable": true
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TaskFocusConfigItemDto"
            },
            "description": "The saved task filter items displayed in the focus panel",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "When the config was created",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "description": "When the config was last updated",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response DTO for a user's task focus panel configuration"
      },
      "TaskFocusConfigItemDto": {
        "type": "object",
        "properties": {
          "savedTaskFilter": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "label": {
            "type": "string",
            "description": "Optional custom label for this item in the focus panel",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "Sort order for display in the focus panel",
            "format": "int32"
          },
          "color": {
            "type": "string",
            "description": "Optional color for visual styling in the focus panel",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response DTO for a single item in the task focus panel configuration"
      },
      "TaskHistoryEventType": {
        "enum": [
          "TaskCreated",
          "TaskStatusChanged",
          "TaskAssigneeChanged",
          "StepStatusChanged",
          "StepAssigneeChanged"
        ],
        "type": "string"
      },
      "TaskItemDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique identifier within the tenant",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The name of the task",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "The description of the task",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/TaskItemStatus"
          },
          "isProjected": {
            "type": "boolean",
            "description": "Whether this task is projected (computed on the fly, not yet saved) or materialised (a saved task)"
          },
          "timeEstimateMinutes": {
            "type": "integer",
            "description": "The estimated time to complete the task, in whole minutes.",
            "format": "int32",
            "nullable": true
          },
          "startDate": {
            "type": "string",
            "description": "When the task starts",
            "format": "date"
          },
          "dueDate": {
            "type": "string",
            "description": "When the task is due",
            "format": "date"
          },
          "isOverdue": {
            "type": "boolean",
            "description": "Indicates if the task is overdue (DueDate is before today and status is not Completed or Skipped)",
            "readOnly": true
          },
          "statutoryDueDate": {
            "type": "string",
            "description": "The statutory due date for compliance tasks (if applicable)",
            "format": "date",
            "nullable": true
          },
          "clients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CodeAndNameDto"
            },
            "description": "The clients this task is associated with",
            "nullable": true
          },
          "primaryClient": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "assignedUser": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "assignedTeam": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "createdDate": {
            "type": "string",
            "description": "When the task was created",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "description": "When the task was last updated",
            "format": "date-time",
            "nullable": true
          },
          "clientBillableService": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "clientPipeline": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "recurringTask": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "workflow": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "category": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "workflowSteps": {
            "type": "integer",
            "description": "The total number of workflow steps for this task",
            "format": "int32",
            "nullable": true
          },
          "workflowStepsComplete": {
            "type": "integer",
            "description": "The number of workflow steps completed for this task",
            "format": "int32",
            "nullable": true
          },
          "workflowStepEstimateMinutes": {
            "type": "integer",
            "description": "Summed estimated minutes of the task's non-omitted workflow steps. Null when the\ntask has no workflow or none of its steps carry an estimate. When present this is\nthe task's effective time estimate, overriding TimeEstimateMinutes.",
            "format": "int32",
            "nullable": true
          },
          "checklist": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChecklistItemDto"
            },
            "description": "Checklist items for this task",
            "nullable": true
          },
          "latestNoteContent": {
            "type": "string",
            "description": "The most recent note/comment on this task",
            "nullable": true
          },
          "latestNoteDate": {
            "type": "string",
            "description": "When the most recent note was created",
            "format": "date-time",
            "nullable": true
          },
          "workflowStepDetails": {
            "$ref": "#/components/schemas/WorkflowStepDetailsDto"
          }
        },
        "additionalProperties": false,
        "description": "A task, either standalone or a workflow step (with parent task context)"
      },
      "TaskItemDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TaskItemDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "TaskItemHistoryEventDto": {
        "type": "object",
        "properties": {
          "timestamp": {
            "type": "string",
            "description": "When the change happened (UTC)",
            "format": "date-time"
          },
          "eventType": {
            "$ref": "#/components/schemas/TaskHistoryEventType"
          },
          "stepName": {
            "type": "string",
            "description": "The name of the workflow step the event relates to. Null for task-level events.",
            "nullable": true
          },
          "fromStatus": {
            "$ref": "#/components/schemas/TaskItemStatus"
          },
          "toStatus": {
            "$ref": "#/components/schemas/TaskItemStatus"
          },
          "fromAssigneeUser": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "fromAssigneeTeam": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "toAssigneeUser": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "toAssigneeTeam": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "stage": {
            "$ref": "#/components/schemas/ClientBillableServiceStageDto"
          },
          "changedByUser": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "changedByClientName": {
            "type": "string",
            "description": "Display name of the external (client) actor that made the change — the contact\nname resolved at write time, falling back to their email. Null for staff/system changes.",
            "nullable": true
          },
          "changedByType": {
            "$ref": "#/components/schemas/AuditUserType"
          }
        },
        "additionalProperties": false,
        "description": "A single event in a task's history timeline — a status or assignee change\non the task itself or one of its workflow steps."
      },
      "TaskItemNoteSortField": {
        "enum": [
          "Date",
          "UpdatedDate"
        ],
        "type": "string"
      },
      "TaskItemSortField": {
        "enum": [
          "Name",
          "DueDate",
          "StartDate",
          "Category",
          "ClientName",
          "AssignedUser",
          "StatutoryDueDate"
        ],
        "type": "string"
      },
      "TaskItemStatus": {
        "enum": [
          "NotStarted",
          "InProgress",
          "Blocked",
          "Completed",
          "Skipped"
        ],
        "type": "string"
      },
      "TaskStartConfigDto": {
        "type": "object",
        "properties": {
          "type": {
            "$ref": "#/components/schemas/StartDateType"
          },
          "intervalValue": {
            "type": "integer",
            "description": "Numeric value for the interval between the Start and Due dates. Required when Type is\nRelativeToDue: the Start is set this many units before the Due.",
            "format": "int32",
            "nullable": true
          },
          "intervalUnit": {
            "$ref": "#/components/schemas/RecurrenceUnit"
          },
          "weekDayPatterns": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WeekDayPatternDto"
            },
            "description": "Positional weekday patterns. Required when Type is MonthDay.\nExample: [{ Position: \"First\", Day: \"Monday\" }, { Position: \"Last\", Day: \"Friday\" }]",
            "nullable": true
          },
          "daysOfMonth": {
            "type": "array",
            "items": {
              "type": "integer",
              "format": "int32"
            },
            "description": "Days of month (1-31). Used when Type is SpecificDate.\nExample: [1, 15] for 1st and 15th",
            "nullable": true
          },
          "day": {
            "$ref": "#/components/schemas/WeekDayType"
          },
          "clientDateSourceType": {
            "$ref": "#/components/schemas/ClientDateSourceType"
          },
          "clientDateType": {
            "$ref": "#/components/schemas/ClientDateType"
          },
          "customFieldDefinitionCode": {
            "type": "string",
            "description": "The code of the custom field definition. Required when Type is ClientDate and ClientDateSourceType is CustomField.\nOnly DATE-type custom fields are valid.",
            "nullable": true
          },
          "customFieldDefinitionLabel": {
            "type": "string",
            "description": "The label of the custom field definition. Populated in responses only.",
            "nullable": true
          },
          "timing": {
            "$ref": "#/components/schemas/DaysBeforeOrAfter"
          },
          "offsetDays": {
            "type": "integer",
            "description": "The number of days before or after the client date.\nUsed when Type is ClientDate and Timing is DaysBefore or DaysAfter.\nPaired with OffsetMonths for composite offsets like \"1 month + 7 days\".",
            "format": "int32",
            "nullable": true
          },
          "offsetMonths": {
            "type": "integer",
            "description": "The number of months before or after the client date. Paired with OffsetDays. NULL when no\nmonths portion is needed. Used when Type is ClientDate.",
            "format": "int32",
            "nullable": true
          },
          "date": {
            "type": "string",
            "description": "Specific start date. Used when Type is SpecificDate.\nThis is when the recurring task should first start generating tasks.",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Configuration for when a recurring task should start.\nDifferent properties are required based on the Type value:\n- SpecificDate: Date specifies the start date seed\n- WeekDay: Day specifies which day of the week to run on\n- MonthDay: WeekDayPatterns specifies positional patterns like \"First Monday\"\n- ClientDate: ClientDateType (or CustomFieldDefinitionCode), Timing, OffsetDays, OffsetMonths\n- RelativeToDue: Start derives from Due via IntervalValue + IntervalUnit (Due-driven mode)"
      },
      "TaskSummaryDto": {
        "type": "object",
        "properties": {
          "notStarted": {
            "type": "integer",
            "description": "Count of tasks that are not started",
            "format": "int32"
          },
          "inProgress": {
            "type": "integer",
            "description": "Count of tasks that are in progress",
            "format": "int32"
          },
          "blocked": {
            "type": "integer",
            "description": "Count of tasks that are blocked",
            "format": "int32"
          },
          "completed": {
            "type": "integer",
            "description": "Count of tasks that are completed",
            "format": "int32"
          },
          "total": {
            "type": "integer",
            "description": "Total count of all tasks",
            "format": "int32",
            "readOnly": true
          }
        },
        "additionalProperties": false,
        "description": "DTO for task summary by status"
      },
      "TeamDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this team",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The display name of the team",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Optional description of the team's purpose",
            "nullable": true
          },
          "iconName": {
            "type": "string",
            "description": "Optional Lucide icon name for visual identification",
            "nullable": true
          },
          "color": {
            "type": "string",
            "description": "Optional hex color for visual identification",
            "nullable": true
          },
          "canBeAssignedToTasks": {
            "type": "boolean",
            "description": "Whether this team can be assigned to tasks"
          },
          "canBeAssignedToClients": {
            "type": "boolean",
            "description": "Whether this team can be assigned to clients"
          },
          "members": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CodeAndNameDto"
            },
            "description": "The members of this team",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response DTO for a team"
      },
      "TeamDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TeamDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "TeamSortField": {
        "enum": [
          "Name"
        ],
        "type": "string"
      },
      "TeamWorkloadReportDto": {
        "type": "object",
        "properties": {
          "summary": {
            "$ref": "#/components/schemas/TeamWorkloadSummaryDto"
          },
          "rows": {
            "$ref": "#/components/schemas/TeamWorkloadRowDtoPagedResult"
          },
          "generatedAt": {
            "type": "string",
            "description": "When the report was generated (UTC).",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "The Team Workload & Productivity report: who's carrying how much open work right now,\nand who completed what over the window."
      },
      "TeamWorkloadRowDto": {
        "type": "object",
        "properties": {
          "groupKind": {
            "$ref": "#/components/schemas/ReportGroupKind"
          },
          "groupCode": {
            "type": "string",
            "description": "Entity code (TenantUser or Team code). Null for the unassigned bucket.",
            "nullable": true
          },
          "groupName": {
            "type": "string",
            "description": "Display name for the group.",
            "nullable": true
          },
          "openCount": {
            "type": "integer",
            "description": "Open tasks right now for this assignee.",
            "format": "int32"
          },
          "overdueCount": {
            "type": "integer",
            "description": "Open tasks past their due date right now.",
            "format": "int32"
          },
          "blockedCount": {
            "type": "integer",
            "description": "Open tasks currently blocked.",
            "format": "int32"
          },
          "completedCount": {
            "type": "integer",
            "description": "Tasks completed in the window. For the User grouping this is who actually completed\nthe task; for the Team grouping, the task's assigned team.",
            "format": "int32"
          },
          "avgTurnaroundDays": {
            "type": "number",
            "description": "Average calendar days from planned start to completion. Null when nothing completed.",
            "format": "double",
            "nullable": true
          },
          "onTimePct": {
            "type": "number",
            "description": "Percentage of this group's completions delivered on or before the due date.\nNull when nothing completed.",
            "format": "double",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One row of the Team Workload breakdown table - one assignee's open workload and throughput."
      },
      "TeamWorkloadRowDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TeamWorkloadRowDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "TeamWorkloadSummaryDto": {
        "type": "object",
        "properties": {
          "openCount": {
            "type": "integer",
            "description": "Open tasks right now (Not Started, In Progress, or Blocked).",
            "format": "int32"
          },
          "overdueCount": {
            "type": "integer",
            "description": "Open tasks past their due date right now.",
            "format": "int32"
          },
          "blockedCount": {
            "type": "integer",
            "description": "Open tasks currently blocked.",
            "format": "int32"
          },
          "unassignedCount": {
            "type": "integer",
            "description": "Open tasks with no assigned user or team.",
            "format": "int32"
          },
          "completedCount": {
            "type": "integer",
            "description": "Tasks completed in the window.",
            "format": "int32"
          },
          "avgTurnaroundDays": {
            "type": "number",
            "description": "Average calendar days from planned start to completion over the window's completions.\nNull when nothing completed.",
            "format": "double",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Headline KPIs for the Team Workload report."
      },
      "TemplateType": {
        "enum": [
          "EngagementLetter",
          "Proposal",
          "AdHoc"
        ],
        "type": "string"
      },
      "TemplateVariables": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "description": "Document-level title (e.g., \"Engagement Letter\", \"Annual Proposal\").\nUsed in cover pages and headers.",
            "nullable": true
          },
          "subtitle": {
            "type": "string",
            "description": "Document-level subtitle providing additional context.\nTypically appears below the main title.",
            "nullable": true
          },
          "secondarySubtitle": {
            "type": "string",
            "description": "Optional secondary subtitle for additional document identification.",
            "nullable": true
          },
          "postalAddress": {
            "type": "string",
            "nullable": true
          },
          "addressee": {
            "type": "string",
            "nullable": true
          },
          "date": {
            "type": "string",
            "description": "Pre-formatted ordinal date string (e.g. \"27th June 2025).\nThis is a baked string and cannot be re-formatted. Use {{ Today | formatDate: \"...\" }}\nwhen you need a custom format.",
            "nullable": true
          },
          "logo": {
            "type": "string",
            "description": "URL or base64-encoded image data for the practice logo.\nCan be used with filters like: {{ Logo | width: 200 }}",
            "nullable": true
          },
          "client": {
            "$ref": "#/components/schemas/ClientDto"
          },
          "business": {
            "$ref": "#/components/schemas/BusinessDetailsDto"
          },
          "vat": {
            "$ref": "#/components/schemas/VatPeriodTokens"
          },
          "periodAnchor": {
            "type": "string",
            "description": "Reference date the filing-period tokens (Vat, TaxQuarter, TaxMonth) are resolved against -\nthe source task's start date for task-driven content, else null (today). Internal plumbing,\nread by the rendering service; not a user-facing token.",
            "format": "date",
            "nullable": true
          },
          "clientRegisteredAddress": {
            "type": "string",
            "description": "Single resolved address for letter headers and templates, automatically chosen by client type:\nbusinesses use Companies House registered office (falling back to postal address);\nindividuals and sole traders use the primary contact's address.\nUsage in templates: {{ Client.RegisteredAddress }} (rewritten to ClientRegisteredAddress before parse).",
            "nullable": true
          },
          "clientNiNumber": {
            "type": "string",
            "description": "National Insurance Number sourced from the primary contact, populated only for\nIndividual and Sole Trader clients (other types have no meaningful client-level NI).\nUsage in templates: {{ Client.NiNumber }} (rewritten to ClientNiNumber before parse).",
            "nullable": true
          },
          "clientHomeAddress": {
            "type": "string",
            "description": "Residential (home) address for self-assessment, sourced from the primary contact for\nIndividual and Sole Trader clients; null for company types. Distinct from\nClientRegisteredAddress, which is the business/correspondence address.\nUsage in templates: {{ Client.HomeAddress }} (rewritten to ClientHomeAddress before parse).",
            "nullable": true
          },
          "clientDateOfBirth": {
            "type": "string",
            "description": "Date of birth sourced from the primary contact, populated only for Individual and Sole Trader\nclients; null for company types. DateOnly so it renders short by default and supports formatDate.\nUsage in templates: {{ Client.DateOfBirth }} (rewritten to ClientDateOfBirth before parse).",
            "format": "date",
            "nullable": true
          },
          "clientUtr": {
            "type": "string",
            "description": "Unique Taxpayer Reference resolved by client type: the primary contact's personal UTR for\nIndividual and Sole Trader clients, the business UTR for all other types.\nUsage in templates: {{ Client.Utr }} (rewritten to ClientUtr before parse).",
            "nullable": true
          },
          "clientMaritalStatus": {
            "type": "string",
            "description": "Marital status (friendly display name) sourced from the primary contact, populated only for\nIndividual and Sole Trader clients; null for company types.\nUsage in templates: {{ Client.MaritalStatus }} (rewritten to ClientMaritalStatus before parse).",
            "nullable": true
          },
          "primaryContact": {
            "$ref": "#/components/schemas/ContactDto"
          },
          "billingContact": {
            "$ref": "#/components/schemas/ContactDto"
          },
          "payrollContact": {
            "$ref": "#/components/schemas/ContactDto"
          },
          "accountsContact": {
            "$ref": "#/components/schemas/ContactDto"
          },
          "partner": {
            "$ref": "#/components/schemas/TenantUserDto"
          },
          "manager": {
            "$ref": "#/components/schemas/TenantUserDto"
          },
          "practice": {
            "$ref": "#/components/schemas/PracticeDetailsDto"
          },
          "engagement": {
            "$ref": "#/components/schemas/EngagementDto"
          },
          "proposal": {
            "$ref": "#/components/schemas/EngagementDto"
          },
          "hasProposal": {
            "type": "boolean",
            "description": "Indicates whether the engagement includes a proposal.\nReturns true if Engagement.Type is ProposalAndEngagementLetter.\nUsage in templates: {% if HasProposal %}...{% endif %}",
            "readOnly": true
          },
          "keyDates": {
            "type": "object",
            "additionalProperties": {
              "nullable": true
            },
            "description": "Client key dates keyed by the ClientDateType enum name (e.g., YearEnd, AccountsNextDue).\nValues are typed DateOnly objects so Fluid renders them as dd-MM-yyyy by default\nand the formatDate filter works natively (e.g., {{ KeyDates.YearEnd | formatDate: \"MMMM yyyy\" }}).\nNull/missing dates are stored as empty string.",
            "nullable": true
          },
          "customFields": {
            "type": "object",
            "additionalProperties": {
              "nullable": true
            },
            "description": "Client custom field values keyed by the custom field definition code.\nOnly includes supported types: Text, Number, Date, Boolean.\nValues are stored as typed objects (string, decimal, DateTime, \"Yes\"/\"No\")\nso Fluid filters like formatDate and formatCurrency work natively.\nUsage in templates: {{ CustomFields.cf-vat-number }}, {{ CustomFields.cf-start-date | formatDate: \"MMMM yyyy\" }}",
            "nullable": true
          },
          "htmlBlocks": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Dictionary of custom HTML blocks that can be injected into templates.\nThis is used for dynamic content that is provided by the client at render time,\nsuch as rendered cost tables, custom sections, or other HTML fragments.\nUsage in templates: {{ HtmlBlocks.ProposalCosts }}, {{ HtmlBlocks.CustomSection }}",
            "nullable": true
          },
          "schedules": {
            "$ref": "#/components/schemas/ContentBlockCollection"
          },
          "url": {
            "type": "string",
            "description": "Generic URL for use in templates (e.g., authorization links, callback URLs, external resources).\nUsage in templates: {{ Url }}",
            "nullable": true
          },
          "buttonText": {
            "type": "string",
            "description": "Button text for use in templates (e.g., confirmation button text).\nUsage in templates: {{ ButtonText }}",
            "nullable": true
          },
          "contact": {
            "$ref": "#/components/schemas/ContactDto"
          },
          "summary": {
            "type": "string",
            "description": "Summary or description text (e.g., document summary).\nUsage in templates: {{ Summary }}",
            "nullable": true
          },
          "custom": {
            "type": "object",
            "additionalProperties": {
              "nullable": true
            },
            "description": "User-defined custom token values keyed by token name.\nPopulated from {{ Custom.TokenName }} tokens in templates.\nUsage in templates: {{ Custom.InvoiceRef }}, {{ Custom.ProjectName }}",
            "nullable": true
          },
          "pageNumber": {
            "type": "string",
            "description": "Current page number for PDF rendering.\nSet automatically when rendering PDF footers - converts to Puppeteer span element.\nUsage in templates: {{ PageNumber }}",
            "nullable": true
          },
          "totalPages": {
            "type": "string",
            "description": "Total page count for PDF rendering.\nSet automatically when rendering PDF footers - converts to Puppeteer span element.\nUsage in templates: {{ TotalPages }}",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Root object containing all variables available for document template rendering.\nThis class serves as the data model for Liquid/Fluid template rendering,\nproviding access to client, practice, proposal, and document-level data."
      },
      "TenantCreateRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The name of the tenant organization",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for creating a new tenant organization"
      },
      "TenantDto": {
        "required": [
          "code",
          "name"
        ],
        "type": "object",
        "properties": {
          "code": {
            "minLength": 1,
            "type": "string",
            "description": "The URL-friendly unique identifier for the tenant (used in API paths)"
          },
          "name": {
            "minLength": 1,
            "type": "string",
            "description": "The human-readable name of the tenant"
          },
          "status": {
            "$ref": "#/components/schemas/TenantStatus"
          },
          "createdDate": {
            "type": "string",
            "description": "When the tenant was created",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "description": "When the tenant was last updated",
            "format": "date-time",
            "nullable": true
          },
          "accountingConnection": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "directDebitConnection": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "amlConnection": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "documentStorageConnection": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "hmrcConnection": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "proposalConnection": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "autoCreateClientFolders": {
            "type": "boolean",
            "description": "Whether Sodium automatically creates subfolders for each client under the document storage base folder.\nOnly applicable when an external document storage provider is connected.\nWhen false, users must manually map each client to a pre-existing folder."
          },
          "activeClientCount": {
            "type": "integer",
            "description": "Count of clients with Active status",
            "format": "int32"
          },
          "inactiveClientCount": {
            "type": "integer",
            "description": "Count of clients with Inactive status",
            "format": "int32"
          },
          "prospectClientCount": {
            "type": "integer",
            "description": "Count of clients with Prospect status",
            "format": "int32"
          },
          "lostProspectClientCount": {
            "type": "integer",
            "description": "Count of clients with LostProspect status",
            "format": "int32"
          },
          "servicesCount": {
            "type": "integer",
            "description": "Count of services in the tenant",
            "format": "int32"
          },
          "workFlowsCount": {
            "type": "integer",
            "description": "Count of workflows in the tenant",
            "format": "int32"
          },
          "usersCount": {
            "type": "integer",
            "description": "Count of users in the tenant",
            "format": "int32"
          },
          "kanbanBoardServiceCount": {
            "type": "integer",
            "description": "Count of services with kanban boards enabled",
            "format": "int32"
          },
          "kanbanBoardPipelineCount": {
            "type": "integer",
            "description": "Count of pipelines with kanban boards enabled",
            "format": "int32"
          },
          "salesPipelineEnabled": {
            "type": "boolean",
            "description": "Whether the Sales Pipeline feature is enabled for this tenant. Gates the pipeline UI."
          },
          "proposalsSentThisMonth": {
            "type": "integer",
            "description": "Number of unique proposals sent this calendar month",
            "format": "int32"
          },
          "isSupportAccessEnabled": {
            "type": "boolean",
            "description": "Whether or not support access is enabled, allowing\nsupport agents to access the tenant's data for troubleshooting."
          },
          "canAccessBetaFeatures": {
            "type": "boolean",
            "description": "Whether this tenant can access beta features"
          },
          "isDisabled": {
            "type": "boolean",
            "description": "Whether this tenant is disabled"
          },
          "disabledReason": {
            "type": "string",
            "description": "The reason the tenant was disabled, if applicable",
            "nullable": true
          },
          "isTasksDisabled": {
            "type": "boolean",
            "description": "Whether task materialization is disabled for this tenant"
          },
          "isMissingRequiredBillingInfo": {
            "type": "boolean",
            "description": "Whether this tenant is on a paid plan but hasn't completed billing/DD setup"
          },
          "isSubscriptionCancelled": {
            "type": "boolean",
            "description": "Whether this tenant has cancelled their subscription.\nCancelled tenants retain access until their current subscription ends."
          },
          "lastUserLogin": {
            "type": "string",
            "description": "The most recent login timestamp across all users in this tenant",
            "format": "date-time",
            "nullable": true
          },
          "expiredDate": {
            "type": "string",
            "description": "When the tenant's subscription expired: the EndDate of the most recently ended subscription.\nNull for tenants that have never had a subscription end. Primarily relevant for lapsed trialists and customers.",
            "format": "date-time",
            "nullable": true
          },
          "logoUrl": {
            "type": "string",
            "description": "The URL of the tenant's logo image",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "An organisation (tenant) and its configuration"
      },
      "TenantHolidayDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique code for the holiday",
            "nullable": true
          },
          "date": {
            "type": "string",
            "description": "The date of the holiday (format: yyyy-MM-dd)",
            "format": "date"
          },
          "name": {
            "type": "string",
            "description": "Name of the holiday (e.g., \"Company Anniversary\", \"Office Closure\")",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Tenant-specific custom holiday"
      },
      "TenantHolidayDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TenantHolidayDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "TenantHolidaySortField": {
        "enum": [
          "Date",
          "Name"
        ],
        "type": "string"
      },
      "TenantInfo": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The tenant's unique code",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "The tenant's name",
            "nullable": true
          },
          "joinedDate": {
            "type": "string",
            "description": "When the user was added to this tenant",
            "format": "date-time"
          },
          "accountingConnection": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "directDebitConnection": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "amlConnection": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "documentStorageConnection": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "hmrcConnection": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "proposalConnection": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "autoCreateClientFolders": {
            "type": "boolean",
            "description": "Whether Sodium automatically creates subfolders for each client under the document storage base folder.\nOnly applicable when an external document storage provider is connected."
          },
          "activeClientCount": {
            "type": "integer",
            "description": "Count of clients with Active status",
            "format": "int32"
          },
          "inactiveClientCount": {
            "type": "integer",
            "description": "Count of clients with Inactive status",
            "format": "int32"
          },
          "prospectClientCount": {
            "type": "integer",
            "description": "Count of clients with Prospect status",
            "format": "int32"
          },
          "lostProspectClientCount": {
            "type": "integer",
            "description": "Count of clients with LostProspect status",
            "format": "int32"
          },
          "servicesCount": {
            "type": "integer",
            "description": "Count of services in the tenant",
            "format": "int32"
          },
          "workFlowsCount": {
            "type": "integer",
            "description": "Count of workflows in the tenant",
            "format": "int32"
          },
          "usersCount": {
            "type": "integer",
            "description": "Count of users in the tenant",
            "format": "int32"
          },
          "kanbanBoardServiceCount": {
            "type": "integer",
            "description": "Count of services with kanban boards enabled",
            "format": "int32"
          },
          "kanbanBoardPipelineCount": {
            "type": "integer",
            "description": "Count of pipelines with kanban boards enabled",
            "format": "int32"
          },
          "salesPipelineEnabled": {
            "type": "boolean",
            "description": "Whether the Sales Pipeline feature is enabled for this tenant. Gates the pipeline UI."
          },
          "canAccessBetaFeatures": {
            "type": "boolean",
            "description": "Whether the tenant can access beta features"
          },
          "isDisabled": {
            "type": "boolean",
            "description": "Whether the tenant is disabled"
          },
          "isMissingRequiredBillingInfo": {
            "type": "boolean",
            "description": "Whether the tenant is on a paid plan but hasn't completed billing/DD setup"
          },
          "isSubscriptionCancelled": {
            "type": "boolean",
            "description": "Whether the tenant has cancelled their subscription"
          },
          "role": {
            "$ref": "#/components/schemas/RoleInfo"
          }
        },
        "additionalProperties": false,
        "description": "Information about a tenant that a user belongs to, including statistics and role information"
      },
      "TenantInfoDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Tenant name",
            "nullable": true
          },
          "logoUrl": {
            "type": "string",
            "description": "Logo URL (SAS URL from blob storage)",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Tenant information for engagement acceptance"
      },
      "TenantStatus": {
        "enum": [
          "LapsedTrialist",
          "LapsedCustomer",
          "ActiveTrialist",
          "PendingConversion",
          "PayingCustomer",
          "Freemium"
        ],
        "type": "string"
      },
      "TenantUpdateRequest": {
        "required": [
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "minLength": 1,
            "type": "string",
            "description": "The human-readable name of the tenant"
          },
          "accountingConnectionCode": {
            "type": "string",
            "description": "The code of the accounting connection to use for this tenant\nTo clear it, set to an empty string rather than null.",
            "nullable": true
          },
          "directDebitConnectionCode": {
            "type": "string",
            "description": "The code of the direct debit connection to use for this tenant\nTo clear it, set to an empty string rather than null.",
            "nullable": true
          },
          "amlConnectionCode": {
            "type": "string",
            "description": "The code of the AML connection to use for this tenant\nTo clear it, set to an empty string rather than null.",
            "nullable": true
          },
          "documentStorageConnectionCode": {
            "type": "string",
            "description": "The code of the document storage connection to use for this tenant\nTo clear it, set to an empty string rather than null.",
            "nullable": true
          },
          "hmrcConnectionCode": {
            "type": "string",
            "description": "The code of the HMRC connection to use for this tenant\nTo clear it, set to an empty string rather than null.",
            "nullable": true
          },
          "proposalConnectionCode": {
            "type": "string",
            "description": "The code of the external proposal platform connection to use for this tenant.\nTo clear it, set to an empty string rather than null.",
            "nullable": true
          },
          "autoCreateClientFolders": {
            "type": "boolean",
            "description": "Whether Sodium automatically creates subfolders for each client under the document storage base folder.\nOnly applicable when an external document storage provider is connected.\nWhen false, users must manually map each client to a pre-existing folder.\nIf null, the existing value will not be changed.",
            "nullable": true
          },
          "isSupportAccessEnabled": {
            "type": "boolean",
            "description": "Whether support access is enabled for this tenant.\nIf null, the existing value will not be changed.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for updating a tenant"
      },
      "TenantUserDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this user within the tenant",
            "nullable": true
          },
          "displayName": {
            "type": "string",
            "description": "The display name for the user (returns full name if available, otherwise email)",
            "nullable": true,
            "readOnly": true
          },
          "email": {
            "type": "string",
            "description": "The user's email address",
            "format": "email",
            "nullable": true
          },
          "firstName": {
            "type": "string",
            "description": "The user's first name",
            "nullable": true
          },
          "lastName": {
            "type": "string",
            "description": "The user's last name",
            "nullable": true
          },
          "isSuperAdmin": {
            "type": "boolean",
            "description": "Whether the user is a super admin"
          },
          "isSupportAccess": {
            "type": "boolean",
            "description": "Whether this user is accessing the tenant via support access (not a regular team member)"
          },
          "avatar": {
            "type": "string",
            "description": "The user's avatar URL",
            "nullable": true
          },
          "userCode": {
            "type": "string",
            "description": "The global user code, for linking to admin user records",
            "nullable": true
          },
          "lastLogin": {
            "type": "string",
            "description": "The user's last login timestamp",
            "format": "date-time",
            "nullable": true
          },
          "authProvider": {
            "type": "string",
            "description": "The authentication provider type (Local, Auth0, Google, Facebook, Xero)",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/TenantUserStatus"
          },
          "invitationExpiresOn": {
            "type": "string",
            "description": "When the invitation expires (null if not invited or if joined directly)",
            "format": "date-time",
            "nullable": true
          },
          "invitationAcceptedAt": {
            "type": "string",
            "description": "When the invitation was accepted (null if still pending)",
            "format": "date-time",
            "nullable": true
          },
          "hourlyRate": {
            "type": "number",
            "description": "Charge-out rate per hour for time tracking.\nFalls back to the practice default rate when null.",
            "format": "double",
            "nullable": true
          },
          "tenant": {
            "$ref": "#/components/schemas/TenantInfo"
          }
        },
        "additionalProperties": false,
        "description": "DTO for a user within a tenant, including their role and basic information."
      },
      "TenantUserDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TenantUserDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "TenantUserSortField": {
        "enum": [
          "LastName",
          "FirstName",
          "Email",
          "Status",
          "Role",
          "LastLogin"
        ],
        "type": "string"
      },
      "TenantUserStatus": {
        "enum": [
          "Created",
          "Invited",
          "Active",
          "Disabled",
          "Declined",
          "Deleted"
        ],
        "type": "string"
      },
      "TestEmailBroadcastRequest": {
        "required": [
          "clientCode"
        ],
        "type": "object",
        "properties": {
          "clientCode": {
            "minLength": 1,
            "type": "string",
            "description": "The code of the sample client to render the email for.",
            "example": "acme-ltd"
          }
        },
        "additionalProperties": false,
        "description": "Request to send a test of a broadcast email to the current user.\nThe email is rendered with the sample client's data but sent only to the caller's own address."
      },
      "TestEmailRequest": {
        "type": "object",
        "properties": {
          "recipientEmail": {
            "type": "string",
            "description": "Email address to send the test email to",
            "nullable": true
          },
          "recipientName": {
            "type": "string",
            "description": "Optional name of the recipient",
            "nullable": true
          },
          "subject": {
            "type": "string",
            "description": "Optional custom subject line. Defaults to \"Test Email - Configuration Verification\" if not provided.",
            "nullable": true
          },
          "htmlBody": {
            "type": "string",
            "description": "Optional custom HTML body. Defaults to a standard verification message if not provided.",
            "nullable": true
          },
          "plainTextBody": {
            "type": "string",
            "description": "Optional custom plain text body. Defaults to a standard verification message if not provided.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request to send a test email for verifying configuration"
      },
      "TestEmailResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "description": "Indicates if the test email was sent successfully"
          },
          "message": {
            "type": "string",
            "description": "Human-readable message describing the result",
            "nullable": true
          },
          "error": {
            "type": "string",
            "description": "Error details if the test email failed (null on success)",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response from sending a test email"
      },
      "ThemeFont": {
        "enum": [
          "Arial",
          "Helvetica",
          "TimesNewRoman",
          "Georgia",
          "Verdana",
          "Tahoma",
          "TrebuchetMs",
          "CourierNew",
          "LucidaConsole",
          "Calibri",
          "OpenSans",
          "Roboto",
          "Lato",
          "Montserrat",
          "Poppins",
          "Inter",
          "Nunito",
          "Raleway",
          "SourceSansPro",
          "WorkSans",
          "PlayfairDisplay",
          "Merriweather",
          "Lora",
          "PtSerif",
          "LibreBaskerville",
          "RobotoMono",
          "SourceCodePro",
          "FiraCode",
          "Custom"
        ],
        "type": "string"
      },
      "ThirdPartyConnectionDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The unique code for this connection",
            "nullable": true
          },
          "platform": {
            "type": "string",
            "description": "The platform identifier (e.g., \"Xero\", \"FreeAgent\", \"Sage\", \"QuickBooks\")",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name for the connection",
            "nullable": true
          },
          "authenticationType": {
            "$ref": "#/components/schemas/AuthenticationType"
          },
          "apiKey": {
            "type": "string",
            "description": "The API key (only populated if AuthenticationType is ApiKey)",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/ConnectionStatus"
          },
          "capabilities": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PlatformCapability"
            },
            "description": "Capabilities available from this platform connection (e.g., Accounting, ClientImport)",
            "nullable": true
          },
          "redirectUrl": {
            "type": "string",
            "description": "URL to redirect the user back to after OAuth flow completes",
            "nullable": true
          },
          "authorizationUrl": {
            "type": "string",
            "description": "OAuth authorization URL for initiating the connection flow",
            "nullable": true
          },
          "organization": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "availableOrganizations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CodeAndNameDto"
            },
            "description": "List of available organizations from the connected platform (populated during OAuth callback)",
            "nullable": true
          },
          "supportsMultipleStorageLocations": {
            "type": "boolean",
            "description": "Whether this connection supports assigning different storage locations to individual\nclients (e.g. per-client SharePoint sites). When true, the storage-locations endpoint\nis available and the frontend should show a location picker on client folder assignment."
          },
          "createdDate": {
            "type": "string",
            "description": "When the connection was created",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "description": "When the connection was last updated",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Represents an OAuth or API key connection to a third-party platform such as Xero, FreeAgent, Sage, or QuickBooks.\nUsed for integrating accounting platforms, client imports, and other external services."
      },
      "ThirdPartyConnectionDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ThirdPartyConnectionDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "ThirdPartyConnectionSortField": {
        "enum": [
          "Name",
          "Platform"
        ],
        "type": "string"
      },
      "ThirdPartyPlatformMetadata": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string",
            "nullable": true
          },
          "displayName": {
            "type": "string",
            "nullable": true
          },
          "authenticationType": {
            "type": "string",
            "nullable": true
          },
          "capabilities": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          },
          "iconUrl": {
            "type": "string",
            "nullable": true
          },
          "logoUrl": {
            "type": "string",
            "nullable": true
          },
          "isBeta": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "TimeBillingLineMode": {
        "enum": [
          "Combined",
          "PerEntry"
        ],
        "type": "string"
      },
      "TimeEntryDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique code for the time entry",
            "nullable": true
          },
          "user": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "entryDate": {
            "type": "string",
            "description": "The day the work was done (format: yyyy-MM-dd)",
            "format": "date"
          },
          "durationMinutes": {
            "type": "integer",
            "description": "How long the work took, in minutes",
            "format": "int32"
          },
          "startTime": {
            "type": "string",
            "description": "When the work started (UTC) — populated for timer-logged entries, optional otherwise",
            "format": "date-time",
            "nullable": true
          },
          "endTime": {
            "type": "string",
            "description": "When the work ended (UTC) — populated for timer-logged entries, optional otherwise",
            "format": "date-time",
            "nullable": true
          },
          "blocks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TimerBlockDto"
            },
            "description": "The work blocks the entry was logged from, for timer-logged entries; empty for\nmanual entries. When present, StartTime, EndTime and DurationMinutes are derived\nfrom the blocks (span start, span end, summed working time) and are read-only —\nthe summed duration can be less than the span when the timer was paused.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "What the time was spent on",
            "nullable": true
          },
          "client": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "taskItem": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "workflowStep": {
            "$ref": "#/components/schemas/LinkedWorkflowStepDto"
          },
          "isBillable": {
            "type": "boolean",
            "description": "Whether this time can be billed to the client"
          },
          "hourlyRate": {
            "type": "number",
            "description": "Charge-out rate per hour snapshotted on the entry",
            "format": "double",
            "nullable": true
          },
          "billedLineItemCode": {
            "type": "string",
            "description": "The code of the billing line item this entry was billed on (null until billed)",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "When the entry was created",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "description": "When the entry was last updated",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A recorded block of time worked by a team member"
      },
      "TimeEntryDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TimeEntryDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "TimeEntrySortField": {
        "enum": [
          "EntryDate",
          "DurationMinutes",
          "ClientName",
          "UserName",
          "IsBillable"
        ],
        "type": "string"
      },
      "TimeRecordingSettingsDto": {
        "type": "object",
        "properties": {
          "timeTrackingEnabled": {
            "type": "boolean",
            "description": "Whether time tracking is enabled for this tenant.\nWhen disabled, no time tracking UI is shown anywhere in the app."
          },
          "requireClientOrTask": {
            "type": "boolean",
            "description": "When true, every time entry must be linked to a client or a task"
          },
          "billableByDefault": {
            "type": "boolean",
            "description": "When true, new time entries and timers start as billable"
          },
          "defaultHourlyRate": {
            "type": "number",
            "description": "Default charge-out rate per hour for billable time entries,\nused when the team member has no rate of their own",
            "format": "double",
            "nullable": true
          },
          "billingLineMode": {
            "$ref": "#/components/schemas/TimeBillingLineMode"
          },
          "autoTimerEnabled": {
            "type": "boolean",
            "description": "When true, starting a workflow step (or a task with no workflow) starts a timer\nfor the acting user linked to it, and completing or skipping it stops the linked\ntimer and logs the time"
          }
        },
        "additionalProperties": false,
        "description": "Tenant-level settings for time recording"
      },
      "TimerBlockDto": {
        "type": "object",
        "properties": {
          "startedAt": {
            "type": "string",
            "description": "When this block of work started (UTC), for wall-clock blocks",
            "format": "date-time",
            "nullable": true
          },
          "endedAt": {
            "type": "string",
            "description": "When this block of work ended (UTC), or null while it is still running",
            "format": "date-time",
            "nullable": true
          },
          "minutes": {
            "type": "integer",
            "description": "The block's duration in minutes, for blocks recorded as an amount of time\nrather than a wall-clock span",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "One block of work on a timer or time entry — either a wall-clock span (start\nand end time) or a plain number of minutes. When Minutes is set it is the\nblock's duration and any times are just context. A block with a start but no\nend and no minutes is still running; no open block means the timer is paused."
      },
      "TrackExternalFileRequest": {
        "type": "object",
        "properties": {
          "externalFileId": {
            "type": "string",
            "description": "The platform-specific file identifier (e.g., Box file ID)",
            "nullable": true
          },
          "fileName": {
            "type": "string",
            "description": "The original file name from the provider",
            "nullable": true
          },
          "fileSize": {
            "type": "integer",
            "description": "File size in bytes",
            "format": "int64"
          },
          "title": {
            "type": "string",
            "description": "The title for the document in Sodium",
            "nullable": true
          },
          "summary": {
            "type": "string",
            "description": "A brief summary or description",
            "nullable": true
          },
          "date": {
            "type": "string",
            "description": "The date the document is dated",
            "format": "date"
          },
          "documentCategoryCode": {
            "type": "string",
            "description": "The document category code",
            "nullable": true
          },
          "visibleInClientPortal": {
            "type": "boolean",
            "description": "Whether this document is visible in the client portal"
          }
        },
        "additionalProperties": false,
        "description": "Request to track an existing external file in our system, creating a ClientDocument\nrecord that references the file by its platform-specific ID. No file upload required."
      },
      "UnbilledTimeClientDto": {
        "type": "object",
        "properties": {
          "client": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "unbilledMinutes": {
            "type": "integer",
            "description": "Total unbilled billable minutes for the client",
            "format": "int32"
          },
          "entryCount": {
            "type": "integer",
            "description": "Number of unbilled billable entries for the client",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "A client with unbilled billable time, and how much of it there is"
      },
      "UnbilledTimeClientDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UnbilledTimeClientDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "UpcomingDeadlineBucketDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Bucket key for deep-links: \"overdue\", \"0-7\", \"8-14\", \"15-30\", or \"31+\".",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name for the bucket.",
            "nullable": true
          },
          "count": {
            "type": "integer",
            "description": "Open tasks whose deadline falls in this bucket.",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "One days-remaining bucket of the upcoming-deadlines snapshot."
      },
      "UpdateAiSettingsRequest": {
        "type": "object",
        "properties": {
          "useCustomKey": {
            "type": "boolean",
            "description": "Whether to use a custom OpenAI API key instead of the shared platform key"
          },
          "customKey": {
            "type": "string",
            "description": "The custom OpenAI API key (only used if UseCustomKey is true)",
            "nullable": true
          },
          "model": {
            "type": "string",
            "description": "The AI model identifier to use (e.g., \"gpt-4\", \"gpt-3.5-turbo\", or \"default\" for platform default)",
            "nullable": true
          },
          "useBritishEnglish": {
            "type": "boolean",
            "description": "Whether to use British English spelling and conventions in AI-generated content"
          },
          "context": {
            "$ref": "#/components/schemas/AiContext"
          },
          "modelServicesScheduleContentCode": {
            "type": "string",
            "description": "Code of the content block that provides context/instructions for AI when generating service schedule descriptions",
            "nullable": true
          },
          "modelProposalsContentCode": {
            "type": "string",
            "description": "Code of the content block that provides context/instructions for AI when generating proposal content",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for updating AI settings for a tenant"
      },
      "UpdateAmlContactRequest": {
        "type": "object",
        "properties": {
          "firstName": {
            "type": "string",
            "nullable": true
          },
          "middleName": {
            "type": "string",
            "nullable": true
          },
          "lastName": {
            "type": "string",
            "nullable": true
          },
          "email": {
            "type": "string",
            "nullable": true
          },
          "phone": {
            "type": "string",
            "nullable": true
          },
          "dateOfBirth": {
            "type": "string",
            "nullable": true
          },
          "companiesHousePersonalCode": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request to update a contact in the AML platform. All fields are optional — only provided fields are sent."
      },
      "UpdateBillableServiceRequest": {
        "required": [
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "minLength": 1,
            "type": "string",
            "description": "The name of the service"
          },
          "description": {
            "type": "string",
            "description": "The description of the service",
            "nullable": true
          },
          "clientTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientType"
            },
            "description": "The types of clients this service is applicable to.\nAn empty list means the service is applicable to all client types.",
            "nullable": true
          },
          "agentAuthorisations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AgentAuthorisationType"
            },
            "description": "The HMRC agent authorisation types relevant to this service",
            "nullable": true
          },
          "isArchived": {
            "type": "boolean",
            "description": "Indicates whether this service is archived (inactive)"
          },
          "accountingCode": {
            "maxLength": 20,
            "minLength": 0,
            "type": "string",
            "description": "The accounting code for this service (max 20 characters)",
            "nullable": true
          },
          "defaultManagedByUserCode": {
            "type": "string",
            "description": "The code of the user who is the default manager for this service",
            "nullable": true
          },
          "serviceScheduleContentCode": {
            "type": "string",
            "description": "The code of the content block to use for service schedule",
            "nullable": true
          },
          "proposalContentCode": {
            "type": "string",
            "description": "The code of the content block to use for proposals",
            "nullable": true
          },
          "category": {
            "$ref": "#/components/schemas/ServiceCategory"
          },
          "vatRate": {
            "$ref": "#/components/schemas/VatRate"
          },
          "pricingMode": {
            "$ref": "#/components/schemas/ServicePricingMode"
          },
          "pricingTiers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BillableServicePricingTierDto"
            },
            "description": "Custom pricing tiers. Required when PricingMode = CustomTiers.",
            "nullable": true
          },
          "showKanbanBoard": {
            "type": "boolean",
            "description": "Whether this service should appear on the Boards kanban view"
          },
          "stages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BillableServiceStageDto"
            },
            "description": "User-defined workflow stages for this service",
            "nullable": true
          },
          "pricing": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BillableServicePricingOptionDto"
            },
            "description": "The pricing options for this service",
            "nullable": true
          },
          "pricingFactors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PricingFactorDto"
            },
            "description": "The pricing factors that can affect the service pricing calculations",
            "nullable": true
          },
          "pcrItemCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The codes of professional clearance request items for this service",
            "nullable": true
          },
          "invoiceLineDescriptionTemplate": {
            "maxLength": 500,
            "minLength": 0,
            "type": "string",
            "description": "Smart name token template for invoice line descriptions (e.g. \"{{ ServiceName }} - {{ Month }} {{ Year }}\")",
            "nullable": true
          },
          "setupFee": {
            "minimum": 0,
            "type": "number",
            "description": "Optional one-off setup fee charged when the service is first billed for a client.\nNull means no setup fee.",
            "format": "double",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for updating an existing billable service"
      },
      "UpdateClientAgentAuthorisationRequest": {
        "required": [
          "authorisationType",
          "status"
        ],
        "type": "object",
        "properties": {
          "authorisationType": {
            "$ref": "#/components/schemas/AgentAuthorisationType"
          },
          "status": {
            "$ref": "#/components/schemas/AgentAuthorisationStatus"
          }
        },
        "additionalProperties": false
      },
      "UpdateClientBillableServiceRequest": {
        "required": [
          "billableServiceCode",
          "billingFrequency",
          "startDate"
        ],
        "type": "object",
        "properties": {
          "billableServiceCode": {
            "minLength": 1,
            "type": "string",
            "description": "The code of the billable service to assign to this client"
          },
          "billingFrequency": {
            "$ref": "#/components/schemas/BillingFrequency"
          },
          "price": {
            "minimum": 0,
            "type": "number",
            "description": "The base price for this client's service (before any adjustment).\nThe final price is: Price + (Price * PriceAdjustmentPercentage / 100) + PriceAdjustmentFixedAmount.\nRequired when OverridePricing = true; ignored when OverridePricing = false (price comes from BillableService).",
            "format": "double",
            "nullable": true
          },
          "overridePricing": {
            "type": "boolean",
            "description": "Indicates whether to use a custom Price value instead of BillableService pricing\nIf true: Must provide Price value\nIf false: Price is loaded from BillableService, and the client-level adjustment is applied"
          },
          "priceAdjustmentPercentage": {
            "type": "number",
            "description": "Percentage contribution from selected Percentage-mode pricing factors (positive or negative). Use -10 for 10% discount, 20 for 20% markup. Defaults to 0.",
            "format": "double"
          },
          "priceAdjustmentFixedAmount": {
            "type": "number",
            "description": "Absolute currency contribution from selected FixedAmount-mode pricing factors (positive or negative). Defaults to 0.",
            "format": "double"
          },
          "startDate": {
            "type": "string",
            "description": "The start date for this service",
            "format": "date-time"
          },
          "endDate": {
            "type": "string",
            "description": "The end date for this service (optional - null means ongoing)",
            "format": "date-time",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/ServiceStatus"
          },
          "managedByUserCode": {
            "type": "string",
            "description": "The code of the user managing this service",
            "nullable": true
          },
          "pricingAnswers": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "The pricing factor answers that determined the final price\nKey: Question, Value: Answer",
            "nullable": true
          },
          "pricingTierCode": {
            "type": "string",
            "description": "The code of the custom pricing tier to apply. Required when the BillableService uses CustomTiers and OverridePricing = false.",
            "nullable": true
          },
          "stageCode": {
            "type": "string",
            "description": "The code of the current workflow stage to set on this service (optional)",
            "nullable": true
          },
          "servicePackageCode": {
            "type": "string",
            "description": "The code of the service package this service was created from, if any.\nLinks the service to its originating package for display and pricing purposes.",
            "nullable": true
          },
          "setupFee": {
            "minimum": 0,
            "type": "number",
            "description": "The one-off setup fee for this client's service. Null means no setup fee.\nWhen OverrideSetupFee = false, pass the BillableService.SetupFee default (or null).\nWhen OverrideSetupFee = true, pass the custom fee (null/0 removes the fee for this client).",
            "format": "double",
            "nullable": true
          },
          "overrideSetupFee": {
            "type": "boolean",
            "description": "Indicates whether to use a custom SetupFee value instead of the BillableService default"
          },
          "autoInvoice": {
            "type": "boolean",
            "description": "Whether this service should automatically generate invoice line items"
          },
          "nextBillingDate": {
            "type": "string",
            "description": "The next date a billable line item should be generated. When omitted and AutoInvoice = true,\ndefaults to StartDate advanced by one BillingFrequency period.",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for updating an existing client billable service assignment"
      },
      "UpdateClientBillableServiceStageRequest": {
        "type": "object",
        "properties": {
          "stageCode": {
            "type": "string",
            "description": "The code of the stage to move the client to. Null to clear the stage.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for updating a client billable service stage (kanban drag-and-drop)"
      },
      "UpdateClientBillingLineItemRequest": {
        "required": [
          "description"
        ],
        "type": "object",
        "properties": {
          "description": {
            "maxLength": 500,
            "minLength": 1,
            "type": "string",
            "description": "The invoice line description"
          },
          "quantity": {
            "type": "number",
            "description": "The quantity",
            "format": "double"
          },
          "unitPrice": {
            "type": "number",
            "description": "The unit price",
            "format": "double"
          },
          "vatRate": {
            "$ref": "#/components/schemas/VatRate"
          },
          "accountingCode": {
            "maxLength": 20,
            "type": "string",
            "description": "The accounting/nominal code (optional)",
            "nullable": true
          },
          "periodStart": {
            "type": "string",
            "description": "Start of the service period covered (optional)",
            "format": "date-time",
            "nullable": true
          },
          "periodEnd": {
            "type": "string",
            "description": "End of the service period covered (optional)",
            "format": "date-time",
            "nullable": true
          },
          "billingDate": {
            "type": "string",
            "description": "Target invoice date",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "Request to update a billing line item"
      },
      "UpdateClientBillingLineItemStatusRequest": {
        "required": [
          "status"
        ],
        "type": "object",
        "properties": {
          "status": {
            "$ref": "#/components/schemas/ClientBillingLineItemStatus"
          }
        },
        "additionalProperties": false,
        "description": "Request to update the status of a billing line item"
      },
      "UpdateClientBillingSettingsRequest": {
        "type": "object",
        "properties": {
          "clientBillingEnabled": {
            "type": "boolean",
            "description": "Whether recurring client billing features are enabled for this tenant"
          },
          "defaultInvoiceDayOfMonth": {
            "type": "integer",
            "description": "Default day of month (1-28) for automatic invoicing on new clients. Null means no default.",
            "format": "int32",
            "nullable": true
          },
          "defaultInvoicePaymentTermDays": {
            "type": "integer",
            "description": "Default payment terms in days for generated invoices on new clients (e.g. 30)",
            "format": "int32",
            "nullable": true
          },
          "defaultLineItemApprovalRequired": {
            "type": "boolean",
            "description": "Default for whether generated line items require manual approval before invoicing on new clients"
          },
          "defaultAccountingCode": {
            "type": "string",
            "description": "Default accounting/nominal code for new billable services and manual line items",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request to update client billing settings for the tenant"
      },
      "UpdateClientContactRequest": {
        "required": [
          "types"
        ],
        "type": "object",
        "properties": {
          "role": {
            "type": "string",
            "description": "The role of the contact within this client relationship",
            "nullable": true
          },
          "types": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientContactType"
            },
            "description": "The type of contact relationship"
          },
          "contact": {
            "$ref": "#/components/schemas/ContactDto"
          },
          "resignedDate": {
            "type": "string",
            "description": "Date the contact resigned their officer role for this client. Usually populated by the\nCompanies House officer stream; user-editable so it can also be set manually (or cleared).",
            "format": "date",
            "nullable": true
          },
          "ceasedDate": {
            "type": "string",
            "description": "Date the contact ceased being a Person with Significant Control for this client. Usually\npopulated by the Companies House PSC stream; user-editable so it can also be set manually.",
            "format": "date",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for updating a client-contact relationship"
      },
      "UpdateClientDataFieldDto": {
        "type": "object",
        "properties": {
          "fieldType": {
            "$ref": "#/components/schemas/DataFormQuestionType"
          },
          "clientField": {
            "$ref": "#/components/schemas/ClientCsvTargetField"
          },
          "customFieldDefinitionCode": {
            "type": "string",
            "description": "The custom field definition code when FieldType is CustomField.",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "Display order within the step.",
            "format": "int32"
          },
          "instructions": {
            "type": "string",
            "description": "Optional instructions or description for this field (supports template tokens).",
            "nullable": true
          },
          "isRequired": {
            "type": "boolean",
            "description": "Whether this field must be filled before the step can be completed."
          },
          "defaultValue": {
            "type": "string",
            "description": "Optional default value to pre-fill the field with.\nWhen all fields have default values and the step is set to AutoExecute,\nthe step can run automatically without user input.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A single field within an UpdateClientData step configuration."
      },
      "UpdateClientDataStepConfigDto": {
        "type": "object",
        "properties": {
          "fields": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UpdateClientDataFieldDto"
            },
            "description": "The fields to present for updating, ordered by SortOrder.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Configuration for UpdateClientData workflow steps.\nDefines which client/custom fields the user should review and update."
      },
      "UpdateClientDocumentRequest": {
        "type": "object",
        "properties": {
          "documentCategoryCode": {
            "type": "string",
            "description": "The document category code. Optional — if omitted, the document will have no category assigned.",
            "nullable": true
          },
          "title": {
            "type": "string",
            "description": "The title of the document",
            "nullable": true
          },
          "summary": {
            "type": "string",
            "description": "A brief summary or description of the document",
            "nullable": true
          },
          "date": {
            "type": "string",
            "description": "The date the document is dated (not the creation date)",
            "format": "date"
          },
          "visibleInClientPortal": {
            "type": "boolean",
            "description": "Whether this document is visible to the client in the portal. Defaults to true.\nDoes not affect visibility in external storage providers — only controls portal access."
          },
          "portalFolderPath": {
            "type": "string",
            "description": "Folder path controlling where this document appears in the client portal.\nFormat: \"/\" separated folder names, e.g. \"Tax Returns/2026\".\nNull or empty for root-level. Only applies to portal display — does not move the physical file.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "UpdateClientEmailRuleRequest": {
        "required": [
          "value"
        ],
        "type": "object",
        "properties": {
          "value": {
            "maxLength": 255,
            "minLength": 0,
            "type": "string",
            "description": "The email address, domain, or message ID to match.\nEmail addresses (contain '@') match that specific participant.\nDomains (no '@', not a GUID) match all emails from that domain.\nMessage IDs (valid GUID) pin a specific email to this client."
          }
        },
        "additionalProperties": false,
        "description": "Request to update an existing email matching rule.\nProvide an email address (e.g. \"john@acme.com\") to match that specific address,\na domain (e.g. \"acme.com\") to match all emails from that domain,\nor a message ID (GUID) to pin a specific email to this client."
      },
      "UpdateClientLinkRequest": {
        "required": [
          "linkType",
          "url"
        ],
        "type": "object",
        "properties": {
          "url": {
            "minLength": 1,
            "type": "string",
            "description": "The URL of the link",
            "format": "uri"
          },
          "linkType": {
            "$ref": "#/components/schemas/LinkType"
          },
          "displayName": {
            "maxLength": 200,
            "type": "string",
            "description": "Optional display name shown as anchor text instead of the URL",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for updating a client link"
      },
      "UpdateClientNoteRequest": {
        "required": [
          "date",
          "text"
        ],
        "type": "object",
        "properties": {
          "text": {
            "minLength": 1,
            "type": "string",
            "description": "The text content of the note"
          },
          "date": {
            "type": "string",
            "description": "The date/time the note was created",
            "format": "date-time"
          },
          "noteFromUserCode": {
            "type": "string",
            "description": "The code of the user who authored this note. Defaults to the authenticated user if not provided.",
            "nullable": true
          },
          "pinnedLevel": {
            "type": "integer",
            "description": "The pinned level for ordering pinned notes",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for updating a client note"
      },
      "UpdateClientPipelineRequest": {
        "required": [
          "pipelineCode",
          "startDate"
        ],
        "type": "object",
        "properties": {
          "pipelineCode": {
            "minLength": 1,
            "type": "string",
            "description": "The code of the pipeline to place the client on"
          },
          "stageCode": {
            "type": "string",
            "description": "The code of the initial stage (optional — null means no stage yet)",
            "nullable": true
          },
          "managedByUserCode": {
            "type": "string",
            "description": "The code of the user managing this card (optional)",
            "nullable": true
          },
          "startDate": {
            "type": "string",
            "description": "The date the client entered the pipeline",
            "format": "date-time"
          },
          "endDate": {
            "type": "string",
            "description": "The date the client left the pipeline (optional)",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for updating a client's pipeline card (full replacement)"
      },
      "UpdateClientPipelineStageRequest": {
        "type": "object",
        "properties": {
          "stageCode": {
            "type": "string",
            "description": "The code of the stage to move the client to. Null to clear the stage.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for updating a client pipeline card's stage (kanban drag-and-drop)"
      },
      "UpdateClientPortalSettingsRequest": {
        "type": "object",
        "properties": {
          "portalTitle": {
            "type": "string",
            "description": "The title displayed on the client portal",
            "nullable": true
          },
          "designThemeCode": {
            "type": "string",
            "description": "Code of the design theme to apply to the client portal",
            "nullable": true
          },
          "iconImageAssetCode": {
            "type": "string",
            "description": "Code of the image asset to use as the portal icon/favicon",
            "nullable": true
          },
          "showInvoices": {
            "type": "boolean",
            "description": "Whether portal users can view their invoices"
          },
          "showServices": {
            "type": "boolean",
            "description": "Whether portal users can view the services set up for them in Sodium"
          },
          "invitationEmailContentBlockCode": {
            "type": "string",
            "description": "Code of the content block to use for portal invitation emails",
            "nullable": true
          },
          "useIntroPageContentBlock": {
            "type": "boolean",
            "description": "When true, the intro page uses the content block. When false, it uses IntroPageText."
          },
          "introPageContentBlockCode": {
            "type": "string",
            "description": "Code of the content block to use for the intro page",
            "nullable": true
          },
          "introPageText": {
            "type": "string",
            "description": "Raw HTML content for the intro page (used when UseIntroPageContentBlock is false)",
            "nullable": true
          },
          "notifyManagerOnClientDocumentUpload": {
            "type": "boolean",
            "description": "Whether to send an email notification to the client's manager when a document is uploaded via the portal"
          }
        },
        "additionalProperties": false,
        "description": "Request to update client portal settings for the tenant"
      },
      "UpdateClientRequest": {
        "required": [
          "name",
          "type"
        ],
        "type": "object",
        "properties": {
          "name": {
            "minLength": 1,
            "type": "string",
            "description": "The name of the client"
          },
          "type": {
            "$ref": "#/components/schemas/ClientType"
          },
          "internalReference": {
            "type": "string",
            "description": "Optional internal reference number/code for the client",
            "nullable": true
          },
          "managerCode": {
            "type": "string",
            "description": "Code of the user who will manage this client.\nThe user must exist and have access to the tenant.",
            "nullable": true
          },
          "partnerCode": {
            "type": "string",
            "description": "Code of the user who will be the partner for this client.\nThe user must exist and have access to the tenant.",
            "nullable": true
          },
          "associateCode": {
            "type": "string",
            "description": "Code of the user who will be the associate for this client.\nThe user must exist and have access to the tenant.",
            "nullable": true
          },
          "teamCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Codes of teams to assign to this client",
            "nullable": true
          },
          "revenueRangeCode": {
            "type": "string",
            "description": "The revenue range code for this client",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/ClientStatus"
          },
          "accountingCustomerCode": {
            "type": "string",
            "description": "The customer code/ID from the connected accounting platform",
            "nullable": true
          },
          "directDebitMandateId": {
            "type": "string",
            "description": "The mandate ID from the connected direct debit platform",
            "nullable": true
          },
          "amlClientId": {
            "type": "string",
            "description": "The client/account ID from the connected AML platform",
            "nullable": true
          },
          "amlClientName": {
            "type": "string",
            "description": "The display name of the client in the connected AML platform",
            "nullable": true
          },
          "email": {
            "type": "string",
            "description": "The email address for the client",
            "nullable": true
          },
          "telephone": {
            "type": "string",
            "description": "The telephone number for the client",
            "nullable": true
          },
          "contactPreferences": {
            "$ref": "#/components/schemas/ContactPreferencesDto"
          },
          "invoiceDayOfMonth": {
            "type": "integer",
            "description": "Day of month (1-28) for automatic invoicing. Null disables auto-invoicing.",
            "format": "int32",
            "nullable": true
          },
          "invoicePaymentTermDays": {
            "type": "integer",
            "description": "Payment terms in days for generated invoices",
            "format": "int32",
            "nullable": true
          },
          "lineItemApprovalRequired": {
            "type": "boolean",
            "description": "Null = use tenant default. True = require manual approval. False = auto-approve.",
            "nullable": true
          },
          "pclSent": {
            "type": "boolean",
            "description": "Indicates whether a Professional Clearance Letter has been sent for this client"
          },
          "snoozeChasesUntil": {
            "type": "string",
            "description": "Suppresses automated chase emails for this client until this date (chasing resumes on the date itself).\nNull = chases are not snoozed.",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for updating an existing client"
      },
      "UpdateClientRequestSettingsRequest": {
        "type": "object",
        "properties": {
          "documentApprovalEmailContentBlockCode": {
            "type": "string",
            "description": "Code of the content block to use as the email body template for document approval request emails",
            "nullable": true
          },
          "documentRequestOpenedEmailContentBlockCode": {
            "type": "string",
            "description": "Code of the content block to use as the email body template when a document request is opened",
            "nullable": true
          },
          "documentRequestRejectedEmailContentBlockCode": {
            "type": "string",
            "description": "Code of the content block to use as the email body template when a document request submission is rejected",
            "nullable": true
          },
          "documentRequestSubmittedEmailContentBlockCode": {
            "type": "string",
            "description": "Code of the content block to use as the email body template when a document request submission is received",
            "nullable": true
          },
          "clientConfirmationEmailContentBlockCode": {
            "type": "string",
            "description": "Code of the content block to use as the email body template for client confirmation workflow step emails",
            "nullable": true
          },
          "clientChaseEmailContentBlockCode": {
            "type": "string",
            "description": "Code of the content block to use as the email body template for client chase emails",
            "nullable": true
          },
          "dataFormSubmissionEmailContentBlockCode": {
            "type": "string",
            "description": "Code of the content block to use as the email body template for form submission emails",
            "nullable": true
          },
          "chaseDocumentRequestFrequencyDays": {
            "type": "integer",
            "description": "How often (in days) to chase open document requests",
            "format": "int32",
            "nullable": true
          },
          "chaseDocumentApprovalFrequencyDays": {
            "type": "integer",
            "description": "How often (in days) to chase pending document approvals",
            "format": "int32",
            "nullable": true
          },
          "chaseClientConfirmationFrequencyDays": {
            "type": "integer",
            "description": "How often (in days) to chase pending client confirmations",
            "format": "int32",
            "nullable": true
          },
          "chaseDataFormSubmissionFrequencyDays": {
            "type": "integer",
            "description": "How often (in days) to chase pending data form submissions",
            "format": "int32",
            "nullable": true
          },
          "hmrcAuthorisationRequestEmailContentBlockCode": {
            "type": "string",
            "description": "Code of the content block to use as the email body template for HMRC authorisation request emails",
            "nullable": true
          },
          "chaseHmrcAuthorisationFrequencyDays": {
            "type": "integer",
            "description": "How often (in days) to chase pending HMRC agent authorisation requests",
            "format": "int32",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request to update client request and chasing settings for the tenant"
      },
      "UpdateClientSettingsRequest": {
        "type": "object",
        "properties": {
          "clientManager_Enabled": {
            "type": "boolean",
            "description": "Whether the client manager field is enabled for clients"
          },
          "clientManager_Label": {
            "maxLength": 50,
            "type": "string",
            "description": "Optional custom label for the client manager field. Null means use the default.",
            "nullable": true
          },
          "partner_Enabled": {
            "type": "boolean",
            "description": "Whether the partner field is enabled for clients"
          },
          "partner_Label": {
            "maxLength": 50,
            "type": "string",
            "description": "Optional custom label for the partner field. Null means use the default.",
            "nullable": true
          },
          "associate_Enabled": {
            "type": "boolean",
            "description": "Whether the associate field is enabled for clients"
          },
          "associate_Label": {
            "maxLength": 50,
            "type": "string",
            "description": "Optional custom label for the associate field. Null means use the default.",
            "nullable": true
          },
          "internalReference_Enabled": {
            "type": "boolean",
            "description": "Whether the internal reference field is enabled for clients"
          },
          "internalReference_ForceUnique": {
            "type": "boolean",
            "description": "Whether to force internal references to be unique across all clients"
          },
          "internalReference_AutoGenerate": {
            "type": "boolean",
            "description": "Whether to auto-generate the internal reference from the client code on creation"
          },
          "externalLinks_Enabled": {
            "type": "boolean",
            "description": "Whether external links are enabled for clients"
          },
          "companiesHouseSync_Enabled": {
            "type": "boolean",
            "description": "Whether Companies House auto-sync is enabled for this tenant. When off, the\nCompanies House worker does not queue stream events for any of this tenant's clients."
          },
          "team_Enabled": {
            "type": "boolean",
            "description": "Whether the team field is enabled for clients"
          }
        },
        "additionalProperties": false,
        "description": "Request to update client settings for the tenant"
      },
      "UpdateClientThirdPartyMappingRequest": {
        "type": "object",
        "properties": {
          "accountingCustomerCode": {
            "type": "string",
            "description": "The customer code/ID from the connected accounting platform",
            "nullable": true
          },
          "directDebitMandateId": {
            "type": "string",
            "description": "The mandate ID from the connected direct debit platform",
            "nullable": true
          },
          "amlClientId": {
            "type": "string",
            "description": "The client/account ID from the connected AML platform",
            "nullable": true
          },
          "amlClientName": {
            "type": "string",
            "description": "The display name of the client in the connected AML platform",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for updating a client's third-party platform mappings.\nImplements RFC 7396 JSON Merge Patch semantics: only fields present in the\nJSON body are updated; absent fields are left unchanged in the database."
      },
      "UpdateContactRequest": {
        "type": "object",
        "properties": {
          "title": {
            "maxLength": 20,
            "type": "string",
            "description": "The contact's title (e.g., Mr, Mrs, Ms, Dr)",
            "nullable": true
          },
          "firstName": {
            "maxLength": 100,
            "type": "string",
            "description": "The contact's first name",
            "nullable": true
          },
          "middleName": {
            "maxLength": 100,
            "type": "string",
            "description": "The contact's middle name",
            "nullable": true
          },
          "lastName": {
            "maxLength": 100,
            "type": "string",
            "description": "The contact's last name",
            "nullable": true
          },
          "email": {
            "maxLength": 200,
            "type": "string",
            "description": "The contact's email address",
            "nullable": true
          },
          "phone": {
            "maxLength": 50,
            "type": "string",
            "description": "The contact's landline phone number",
            "nullable": true
          },
          "mobile": {
            "maxLength": 50,
            "type": "string",
            "description": "The contact's mobile phone number",
            "nullable": true
          },
          "dateOfBirth": {
            "type": "string",
            "description": "The contact's date of birth",
            "format": "date",
            "nullable": true
          },
          "utr": {
            "type": "string",
            "description": "The contact's Unique Taxpayer Reference (Self Assessment UTR).\nUsed for individuals' personal tax affairs.",
            "nullable": true
          },
          "niNumber": {
            "type": "string",
            "description": "The contact's National Insurance Number.",
            "nullable": true
          },
          "personalCode": {
            "maxLength": 50,
            "type": "string",
            "description": "The contact's Companies House person ID code, used to uniquely identify\nan individual within the Companies House system.",
            "nullable": true
          },
          "address": {
            "type": "string",
            "description": "The contact's address. Only used when the client type is Individual.",
            "nullable": true
          },
          "nationality": {
            "$ref": "#/components/schemas/Nationality"
          },
          "maritalStatus": {
            "$ref": "#/components/schemas/MaritalStatus"
          },
          "isDeceased": {
            "type": "boolean",
            "description": "Whether this contact is deceased"
          },
          "deceasedDate": {
            "type": "string",
            "description": "The date the contact was deceased, if known",
            "format": "date",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "DTO for updating a contact"
      },
      "UpdateContentBlockRequest": {
        "required": [
          "category",
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "maxLength": 200,
            "minLength": 0,
            "type": "string",
            "description": "Display name for the content block"
          },
          "bodyHtml": {
            "type": "string",
            "description": "HTML content of the block with Liquid syntax support",
            "nullable": true
          },
          "description": {
            "maxLength": 500,
            "minLength": 0,
            "type": "string",
            "description": "Optional description explaining the block's purpose and where it should be used",
            "nullable": true
          },
          "category": {
            "$ref": "#/components/schemas/ContentBlockCategory"
          },
          "subjectLine": {
            "maxLength": 500,
            "minLength": 0,
            "type": "string",
            "description": "Optional subject line for email content blocks (only relevant when Category is EmailParts).\nSupports merge field syntax (e.g., {{ Client.Name }}).",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request to update an existing content block"
      },
      "UpdateCsvMappingRequest": {
        "required": [
          "columnMappings",
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "minLength": 1,
            "type": "string",
            "description": "Human-readable display name for this mapping.\nChoose a descriptive name that identifies the CSV format (e.g., 'IRIS Export', 'Xero Contacts').\nRequired.",
            "example": "IRIS Client Export"
          },
          "columnMappings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CsvColumnMappingDto"
            },
            "description": "The column mappings that define how CSV headers map to client fields.\nEach mapping specifies a CSV header and the corresponding target field.\nRequired - must include at least one mapping."
          },
          "matchField": {
            "$ref": "#/components/schemas/CsvImportMatchField"
          }
        },
        "additionalProperties": false,
        "description": "Request to update an existing CSV mapping."
      },
      "UpdateCustomFieldDefinitionRequest": {
        "required": [
          "customFieldGroupCode"
        ],
        "type": "object",
        "properties": {
          "label": {
            "type": "string",
            "nullable": true
          },
          "dataType": {
            "$ref": "#/components/schemas/CustomFieldDataType"
          },
          "options": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          },
          "maxLength": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "lines": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "displayWidth": {
            "$ref": "#/components/schemas/FieldDisplayWidth"
          },
          "booleanDisplayMode": {
            "$ref": "#/components/schemas/BooleanDisplayMode"
          },
          "clientTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientType"
            },
            "description": "The types of clients this custom field is applicable to.\nAn empty list means the field is applicable to all client types.",
            "nullable": true
          },
          "customFieldGroupCode": {
            "minLength": 1,
            "type": "string"
          },
          "isArchived": {
            "type": "boolean"
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          }
        },
        "additionalProperties": false
      },
      "UpdateCustomFieldGroupRequest": {
        "required": [
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "maxLength": 200,
            "minLength": 1,
            "type": "string"
          },
          "parentCustomFieldGroupCode": {
            "type": "string",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "format": "int32"
          }
        },
        "additionalProperties": false
      },
      "UpdateCustomTokenRequest": {
        "required": [
          "name",
          "tokenIdentifier"
        ],
        "type": "object",
        "properties": {
          "name": {
            "maxLength": 120,
            "minLength": 1,
            "type": "string",
            "description": "Human-readable display name for the token (e.g. \"Company Secretary\")"
          },
          "tokenIdentifier": {
            "maxLength": 120,
            "minLength": 1,
            "type": "string",
            "description": "The token identifier used in templates (e.g. \"CompanySecretary\" for {{ Custom.CompanySecretary }}).\nMust be alphanumeric with underscores only. Unique per tenant."
          },
          "description": {
            "maxLength": 500,
            "type": "string",
            "description": "Optional prompt text shown when filling in the token value",
            "nullable": true
          },
          "defaultValue": {
            "maxLength": 500,
            "type": "string",
            "description": "Optional default value pre-populated in the token form",
            "nullable": true
          },
          "displayWidth": {
            "type": "string",
            "description": "Preset display width for the input. Null defaults to Full.",
            "nullable": true
          },
          "lines": {
            "type": "integer",
            "description": "Number of visible text lines. Null renders a single-line input, 2+ renders a textarea.",
            "format": "int32",
            "nullable": true
          },
          "isRichText": {
            "type": "boolean",
            "description": "When true and Lines >= 2, the input renders as a rich text editor instead of a plain textarea."
          }
        },
        "additionalProperties": false,
        "description": "DTO for updating a custom token"
      },
      "UpdateDataFormCategoryRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The display name of the form category",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "DTO for updating a form category"
      },
      "UpdateDataFormRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "introduction": {
            "type": "string",
            "nullable": true
          },
          "dataFormCategoryCode": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/DataFormStatus"
          },
          "defaultMessage": {
            "type": "string",
            "nullable": true
          },
          "sections": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DataFormSectionDto"
            },
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "DTO for updating a form (whole-form save including sections and questions)"
      },
      "UpdateDesignThemeRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Display name for the theme",
            "nullable": true
          },
          "isDefault": {
            "type": "boolean",
            "description": "Whether this should be the default theme for the tenant"
          },
          "heading1": {
            "$ref": "#/components/schemas/FontSettingsDto"
          },
          "heading2": {
            "$ref": "#/components/schemas/FontSettingsDto"
          },
          "heading3": {
            "$ref": "#/components/schemas/FontSettingsDto"
          },
          "body": {
            "$ref": "#/components/schemas/FontSettingsDto"
          },
          "tableHeader": {
            "$ref": "#/components/schemas/FontSettingsDto"
          },
          "tableCell": {
            "$ref": "#/components/schemas/FontSettingsDto"
          },
          "logoUrl": {
            "type": "string",
            "description": "URL to the company logo image",
            "nullable": true
          },
          "primaryColor": {
            "type": "string",
            "description": "Primary brand color in hex format (e.g., \"#000000\")",
            "nullable": true
          },
          "secondaryColor": {
            "type": "string",
            "description": "Secondary brand color in hex format",
            "nullable": true
          },
          "accentColor": {
            "type": "string",
            "description": "Accent color in hex format",
            "nullable": true
          },
          "backgroundColor": {
            "type": "string",
            "description": "Optional page background color in hex format (e.g., \"#FFFFFF\"). Null for transparent/default.",
            "nullable": true
          },
          "linkColor": {
            "type": "string",
            "description": "Optional link color in hex format (e.g., \"#1E88E5\"). Null for default.",
            "nullable": true
          },
          "linkHoverColor": {
            "type": "string",
            "description": "Optional link hover color in hex format (e.g., \"#0D47A1\"). Null for default.",
            "nullable": true
          },
          "primaryButton": {
            "$ref": "#/components/schemas/ButtonStyleDto"
          },
          "secondaryButton": {
            "$ref": "#/components/schemas/ButtonStyleDto"
          },
          "navBackgroundColor": {
            "type": "string",
            "description": "Navigation background color for the client portal (e.g., \"#1e293b\")",
            "nullable": true
          },
          "navTextColor": {
            "type": "string",
            "description": "Navigation text color for the client portal",
            "nullable": true
          },
          "navActiveBackgroundColor": {
            "type": "string",
            "description": "Active navigation item highlight color (supports rgba, e.g., \"rgba(255,255,255,0.15)\")",
            "nullable": true
          },
          "navActiveTextColor": {
            "type": "string",
            "description": "Active navigation item text color",
            "nullable": true
          },
          "cardBackgroundColor": {
            "type": "string",
            "description": "Card/panel background color in the content area",
            "nullable": true
          },
          "borderRadius": {
            "type": "integer",
            "description": "Global corner radius in pixels for cards, buttons, and inputs",
            "format": "int32",
            "nullable": true
          },
          "navFontSize": {
            "type": "number",
            "description": "Font size in points for the client portal navigation bar. Null falls back to body font size.",
            "format": "float",
            "nullable": true
          },
          "faviconUrl": {
            "type": "string",
            "description": "URL to a tenant-specific favicon for the client portal",
            "nullable": true
          },
          "pageMargins": {
            "$ref": "#/components/schemas/MarginsDto"
          },
          "customCSS": {
            "type": "string",
            "description": "Additional custom CSS rules to append to the generated theme CSS",
            "nullable": true
          },
          "headerTextContentBlockCode": {
            "type": "string",
            "description": "Code of the content block to use for document headers.\nPDF only: repeats at the top of each page. When set, PageMarginTop is ignored.",
            "nullable": true
          },
          "headerPageSelection": {
            "$ref": "#/components/schemas/PageSelection"
          },
          "footerContentBlockCode": {
            "type": "string",
            "description": "Code of the content block to use for document footers.\nPDF only: repeats at the bottom of each page.",
            "nullable": true
          },
          "footerPageSelection": {
            "$ref": "#/components/schemas/PageSelection"
          },
          "pageNumberDisplay": {
            "$ref": "#/components/schemas/PageSelection"
          }
        },
        "additionalProperties": false,
        "description": "Request to update an existing design theme"
      },
      "UpdateDirectDebitSettingsRequest": {
        "type": "object",
        "properties": {
          "requestEmailContentBlockCode": {
            "type": "string",
            "description": "Code of the content block to include in the direct debit request email body",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request to update direct debit settings for the tenant"
      },
      "UpdateDocumentCategoryRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The display name of the document category",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "The sort order for displaying document categories",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "DTO for updating a document category"
      },
      "UpdateDocumentRequestRequest": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "description": "Title describing what documents are needed",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Detailed description of what is needed",
            "nullable": true
          },
          "deadline": {
            "type": "string",
            "description": "Optional deadline for the client to respond by",
            "format": "date",
            "nullable": true
          },
          "notifyUserCode": {
            "type": "string",
            "description": "Code of the user to notify when a submission is made",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for updating a document request (only allowed while in Draft status)"
      },
      "UpdateDocumentTemplateRequest": {
        "required": [
          "bodyHtml",
          "name",
          "type"
        ],
        "type": "object",
        "properties": {
          "name": {
            "maxLength": 120,
            "minLength": 1,
            "type": "string",
            "description": "Display name for the template (e.g., \"Standard Engagement Letter\", \"Monthly Report\")"
          },
          "type": {
            "$ref": "#/components/schemas/TemplateType"
          },
          "bodyHtml": {
            "minLength": 1,
            "type": "string",
            "description": "Template body in HTML with Liquid syntax tokens.\nSupported tokens:\n- {{ client.name }} - Client's name\n- {{ client.companyNumber }} - Company registration number\n- {{ tenant.name }} - Your practice name\n- {{ date | date: \"%B %d, %Y\" }} - Current date (formatted)\n- {{ contentBlock \"block-code\" }} - Include a reusable content block\n- {% if client.isVatRegistered %} ... {% endif %} - Conditional content\n- {% for item in services %} ... {% endfor %} - Loop through collections\nCustom tokens can be passed via the Data parameter when rendering."
          },
          "description": {
            "maxLength": 500,
            "type": "string",
            "description": "Optional description explaining the template's purpose and usage",
            "nullable": true
          },
          "isActive": {
            "type": "boolean",
            "description": "Whether this template is available for use. Set to false to disable without deleting."
          },
          "outputNameTemplate": {
            "maxLength": 500,
            "type": "string",
            "description": "Optional template for naming rendered documents.\nSupports {{ token }} placeholders (e.g. \"Engagement Letter - {{ ClientName }} - {{ Month }} {{ Year }}\").\nWhen null or empty, documents use the template's Name.",
            "nullable": true
          },
          "defaultDesignThemeCode": {
            "type": "string",
            "description": "Code of the default design theme to apply when rendering this template.\nIf not specified, falls back to the tenant's default theme.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "UpdateEmailBroadcastRequest": {
        "type": "object",
        "properties": {
          "contentBlockCode": {
            "maxLength": 100,
            "type": "string",
            "description": "Content block code (category: Email) used as the email template.\nMutually exclusive with SubjectLine/BodyHtml — provide one or the other.",
            "nullable": true,
            "example": "client-newsletter"
          },
          "subjectLine": {
            "maxLength": 500,
            "type": "string",
            "description": "Inline email subject line with Liquid template syntax.\nMust be provided together with BodyHtml. Mutually exclusive with ContentBlockCode.",
            "nullable": true,
            "example": "An update for {{ Client.Name }}"
          },
          "bodyHtml": {
            "type": "string",
            "description": "Inline email body HTML with Liquid template syntax.\nMust be provided together with SubjectLine. Mutually exclusive with ContentBlockCode.",
            "nullable": true
          },
          "allContacts": {
            "type": "boolean",
            "description": "When true, every contact of each client with an email address receives the email\nas a To recipient, regardless of contact type. RecipientContactTypes is ignored.",
            "example": false
          },
          "recipientContactTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientContactType"
            },
            "description": "Client contact types for To recipients, resolved per client at send time.\nIgnored when AllContacts is true.",
            "nullable": true
          },
          "recipientUserTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowStepAssignmentType"
            },
            "description": "User types for To recipients (ClientManager, ClientPartner, ClientAssociate, ClientServiceManager),\nresolved per client at send time. TaskOwner and SpecificUser are not applicable for broadcasts.",
            "nullable": true
          },
          "additionalEmailAddresses": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Static email addresses to include as To recipients on every email.",
            "nullable": true
          },
          "ccContactTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientContactType"
            },
            "description": "Client contact types for CC recipients.",
            "nullable": true
          },
          "ccUserTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowStepAssignmentType"
            },
            "description": "User types for CC recipients.",
            "nullable": true
          },
          "ccEmailAddresses": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Static email addresses to include as CC recipients on every email.",
            "nullable": true
          },
          "bccContactTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientContactType"
            },
            "description": "Client contact types for BCC recipients.",
            "nullable": true
          },
          "bccUserTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowStepAssignmentType"
            },
            "description": "User types for BCC recipients.",
            "nullable": true
          },
          "bccEmailAddresses": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Static email addresses to include as BCC recipients on every email.",
            "nullable": true
          },
          "savedViewCode": {
            "maxLength": 100,
            "type": "string",
            "description": "The code of a saved client view whose filter selects which clients to include.\nThe view's criteria are resolved when recipients are resolved, so later changes to\nthe view are picked up until the broadcast is sent. Mutually exclusive with Filter.",
            "nullable": true,
            "example": "active-limited-companies"
          },
          "filter": {
            "$ref": "#/components/schemas/EmailBroadcastFilterDto"
          },
          "excludedClientCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Client codes to exclude from the filter results.",
            "nullable": true
          },
          "additionalClientCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Hand-picked client codes to add on top of the filter results.",
            "nullable": true
          },
          "onlyEmailableClients": {
            "type": "boolean",
            "description": "When true (default), clients whose email contact preference is not set are skipped.",
            "example": true
          },
          "addHeaderFooter": {
            "type": "boolean",
            "description": "When true (default), the tenant's email header and footer content blocks are\nwrapped around the body when the email is rendered.",
            "example": true
          },
          "configCode": {
            "maxLength": 100,
            "type": "string",
            "description": "The email configuration (mailbox) code to send from.\nOmit to use the tenant's default mailbox resolution.",
            "nullable": true,
            "example": "billing-mailbox"
          }
        },
        "additionalProperties": false,
        "description": "Request to update a draft email broadcast.\nPUT is a full replacement — all fields are applied as provided.\nOnly broadcasts with status Draft can be updated.\nSame shape as the create request."
      },
      "UpdateEmailConfigRequest": {
        "type": "object",
        "properties": {
          "fromEmail": {
            "type": "string",
            "description": "Updated sender email address (optional, null to keep existing).\nCannot be changed on OAuth configurations that are currently connected.",
            "nullable": true
          },
          "fromName": {
            "type": "string",
            "description": "Updated sender display name (optional, null to keep existing)",
            "nullable": true
          },
          "isDefault": {
            "type": "boolean",
            "description": "Whether to set this as the tenant's default email configuration.\nCannot be true unless IsSendShared is also true. Null to keep existing.",
            "nullable": true
          },
          "isSendShared": {
            "type": "boolean",
            "description": "Whether all users in the tenant can send emails from this configuration.\nCannot be set to false on the current default config. Null to keep existing.",
            "nullable": true
          },
          "isReadShared": {
            "type": "boolean",
            "description": "Whether all users in the tenant can read the emails received in this mailbox.\nOnly the owner of the configuration can change this. Null to keep existing.",
            "nullable": true
          },
          "signature": {
            "type": "string",
            "description": "Updated HTML email signature (empty string to clear, null to keep existing)",
            "nullable": true
          },
          "smtpSettings": {
            "$ref": "#/components/schemas/SmtpSettingsRequest"
          },
          "oAuthSettings": {
            "$ref": "#/components/schemas/OAuthSettingsRequest"
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for updating an existing email configuration"
      },
      "UpdateEmailSettingsRequest": {
        "type": "object",
        "properties": {
          "emailHeaderContentBlockCode": {
            "type": "string",
            "description": "Code of the content block to include at the top of emails",
            "nullable": true
          },
          "emailFooterContentBlockCode": {
            "type": "string",
            "description": "Code of the content block to include at the bottom of emails",
            "nullable": true
          },
          "designThemeCode": {
            "type": "string",
            "description": "Code of the design theme to apply for email styling",
            "nullable": true
          },
          "replyToEmail": {
            "type": "string",
            "description": "Reply-to email address for system emails",
            "format": "email",
            "nullable": true
          },
          "replyToName": {
            "type": "string",
            "description": "Reply-to display name for system emails",
            "nullable": true
          },
          "useClientManagerEmailMatching": {
            "type": "boolean",
            "description": "When enabled, outbound emails use the connection matching the client's manager email address instead of the default"
          }
        },
        "additionalProperties": false,
        "description": "Request to update email settings for the tenant"
      },
      "UpdateEngagementRequest": {
        "required": [
          "clientCode",
          "date"
        ],
        "type": "object",
        "properties": {
          "clientCode": {
            "minLength": 1,
            "type": "string",
            "description": "Code of the client this engagement belongs to"
          },
          "date": {
            "type": "string",
            "description": "Date of the engagement",
            "format": "date"
          },
          "status": {
            "$ref": "#/components/schemas/EngagementStatus"
          },
          "type": {
            "$ref": "#/components/schemas/EngagementType"
          },
          "manuallyAccepted": {
            "type": "boolean",
            "description": "Indicates whether the engagement was manually accepted (true) or accepted via the online acceptance page (false).\nOnly relevant when Status is set to Accepted.",
            "nullable": true
          },
          "recipientFirstName": {
            "type": "string",
            "description": "First name of the recipient for this engagement",
            "nullable": true
          },
          "recipientLastName": {
            "type": "string",
            "description": "Last name of the recipient for this engagement",
            "nullable": true
          },
          "recipientEmail": {
            "type": "string",
            "description": "Email address of the recipient for this engagement",
            "nullable": true
          },
          "requestDdMandate": {
            "type": "boolean",
            "description": "Per-proposal override for the \"set up Direct Debit\" acceptance step, set on the send screen.\nNull leaves the practice default (from proposal settings) in effect for this proposal.",
            "nullable": true
          },
          "requestAmlOnboarding": {
            "type": "boolean",
            "description": "Per-proposal override for the identity-verification (AML) acceptance step, set on the send screen.\nNull leaves the practice default (from proposal settings) in effect for this proposal.",
            "nullable": true
          },
          "proposalTemplateCode": {
            "type": "string",
            "description": "Code of the template to use for the proposal document",
            "nullable": true
          },
          "lofETemplateCode": {
            "type": "string",
            "description": "Code of the template to use for the letter of engagement (LofE) document",
            "nullable": true
          },
          "clientBillableServiceCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "List of ClientBillableService codes to include in this engagement.\n            \nIMPORTANT: Updating this field will replace ALL existing service snapshots with new ones.\nThe system will create fresh snapshots of each ClientBillableService at its current state.\nThis allows you to update the engagement if service pricing or details have changed.\n            \nThe historical snapshots are stored as JSON and preserve service details even if the original\nClientBillableService is later modified or deleted.\n            \nExample: [\"CBS001\", \"CBS002\", \"CBS003\"]",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for updating an existing engagement"
      },
      "UpdateEngagementSettingsRequest": {
        "type": "object",
        "properties": {
          "introContentBlockCode": {
            "type": "string",
            "description": "Code of the content block to display at the start of engagement acceptance pages",
            "nullable": true
          },
          "thankYouContentBlockCode": {
            "type": "string",
            "description": "Code of the content block to display after engagement acceptance",
            "nullable": true
          },
          "emailContentBlockCode": {
            "type": "string",
            "description": "Code of the content block to include in the engagement email body",
            "nullable": true
          },
          "acceptanceTaskCode": {
            "type": "string",
            "description": "Code of the recurring task template to automatically create when an engagement is accepted",
            "nullable": true
          },
          "notifyClientManagerOnAcceptance": {
            "type": "boolean",
            "description": "Whether to send an email notification to the client manager when an engagement is accepted"
          },
          "notifyPartnerOnAcceptance": {
            "type": "boolean",
            "description": "Whether to send an email notification to the partner when an engagement is accepted"
          },
          "designThemeCode": {
            "type": "string",
            "description": "Code of the design theme to apply to engagement documents and acceptance pages",
            "nullable": true
          },
          "showPracticeName": {
            "type": "boolean",
            "description": "Whether to display the practice name on engagement acceptance pages and documents"
          },
          "attachPDFs": {
            "type": "boolean",
            "description": "Whether to attach engagement PDFs to the engagement email"
          },
          "thankYouEmailContentBlockCode": {
            "type": "string",
            "description": "Code of the content block to use for thank you email sent to client after engagement acceptance",
            "nullable": true
          },
          "requestDdMandate": {
            "type": "boolean",
            "description": "Whether to request a Direct Debit mandate when engagement is accepted"
          },
          "requestAmlOnboarding": {
            "type": "boolean",
            "description": "Whether to request AML onboarding for the main contact when engagement is accepted"
          },
          "amlOnboardingLevelId": {
            "type": "string",
            "description": "The AML platform onboarding level ID to use when creating the onboarding request",
            "nullable": true
          },
          "signaturePageContentBlockCode": {
            "type": "string",
            "description": "Code of the content block to use as the signature page in engagement documents",
            "nullable": true
          },
          "useThirdPartyProposalPlatform": {
            "type": "boolean",
            "description": "Whether to use a third-party platform (e.g., Socket) for proposals instead of native Sodium proposals"
          },
          "addToPipelineOnSend": {
            "type": "boolean",
            "description": "Whether to add the client to a sales pipeline when their proposal is first sent"
          },
          "onSendPipelineCode": {
            "type": "string",
            "description": "Code of the sales pipeline clients are added to when their proposal is first sent",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request to update engagement settings for the tenant"
      },
      "UpdateImageAssetRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Display name for the image asset",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Optional description of the image asset",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request to update an existing image asset"
      },
      "UpdateOnboardingTaskTemplateRequest": {
        "required": [
          "billableServiceCode"
        ],
        "type": "object",
        "properties": {
          "billableServiceCode": {
            "minLength": 1,
            "type": "string",
            "description": "Code of the billable service this template belongs to"
          },
          "name": {
            "type": "string",
            "description": "The name of the onboarding task",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "The description of the onboarding task",
            "nullable": true
          },
          "timeEstimateMinutes": {
            "type": "integer",
            "description": "The estimated time to complete the task, in whole minutes.",
            "format": "int32",
            "nullable": true
          },
          "dueDateOffsetDays": {
            "type": "integer",
            "description": "Days after service start date for the task due date",
            "format": "int32"
          },
          "assignmentType": {
            "$ref": "#/components/schemas/AssignmentType"
          },
          "assignedUserCode": {
            "type": "string",
            "description": "Code of the user to assign tasks to (only used if AssignmentType is SpecificUser)",
            "nullable": true
          },
          "assignedTeamCode": {
            "type": "string",
            "description": "Code of the team to assign tasks to (optional, independent of AssignmentType)",
            "nullable": true
          },
          "workflowCode": {
            "type": "string",
            "description": "Code of the workflow template to apply to generated tasks",
            "nullable": true
          },
          "categoryCode": {
            "type": "string",
            "description": "Code of the category to apply to generated tasks",
            "nullable": true
          },
          "checklist": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChecklistItemDto"
            },
            "description": "Checklist items for this onboarding task template",
            "nullable": true
          },
          "active": {
            "type": "boolean",
            "description": "Whether this template is active"
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for updating an onboarding task template"
      },
      "UpdatePipelineOnboardingTaskTemplateRequest": {
        "required": [
          "pipelineCode"
        ],
        "type": "object",
        "properties": {
          "pipelineCode": {
            "minLength": 1,
            "type": "string",
            "description": "Code of the pipeline this template belongs to"
          },
          "name": {
            "type": "string",
            "description": "The name of the intake task",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "The description of the intake task",
            "nullable": true
          },
          "timeEstimateMinutes": {
            "type": "integer",
            "description": "The estimated time to complete the task, in whole minutes.",
            "format": "int32",
            "nullable": true
          },
          "dueDateOffsetDays": {
            "type": "integer",
            "description": "Days after the card's start date for the task due date",
            "format": "int32"
          },
          "assignmentType": {
            "$ref": "#/components/schemas/AssignmentType"
          },
          "assignedUserCode": {
            "type": "string",
            "description": "Code of the user to assign tasks to (only used if AssignmentType is SpecificUser)",
            "nullable": true
          },
          "assignedTeamCode": {
            "type": "string",
            "description": "Code of the team to assign tasks to (optional, independent of AssignmentType)",
            "nullable": true
          },
          "workflowCode": {
            "type": "string",
            "description": "Code of the workflow template to apply to generated tasks",
            "nullable": true
          },
          "categoryCode": {
            "type": "string",
            "description": "Code of the category to apply to generated tasks",
            "nullable": true
          },
          "checklist": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChecklistItemDto"
            },
            "description": "Checklist items for this intake task template",
            "nullable": true
          },
          "active": {
            "type": "boolean",
            "description": "Whether this template is active"
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for updating a pipeline intake task template"
      },
      "UpdatePipelineRequest": {
        "required": [
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "minLength": 1,
            "type": "string",
            "description": "The name of the pipeline"
          },
          "description": {
            "type": "string",
            "description": "The description of the pipeline",
            "nullable": true
          },
          "isArchived": {
            "type": "boolean",
            "description": "Indicates whether this pipeline is archived (inactive)"
          },
          "defaultManagedByUserCode": {
            "type": "string",
            "description": "The code of the user who is the default manager for this pipeline",
            "nullable": true
          },
          "showKanbanBoard": {
            "type": "boolean",
            "description": "Whether this pipeline should appear on the Boards kanban view"
          },
          "stages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PipelineStageDto"
            },
            "description": "User-defined stages for this pipeline",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for updating an existing sales pipeline (full replacement)"
      },
      "UpdatePortalUserStatusRequest": {
        "type": "object",
        "properties": {
          "isActive": {
            "type": "boolean",
            "description": "Whether the portal user should be active."
          }
        },
        "additionalProperties": false,
        "description": "Request to activate or deactivate a portal user."
      },
      "UpdatePracticeDetailsRequest": {
        "required": [
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "minLength": 1,
            "type": "string",
            "description": "Official name of the accounting practice or firm"
          },
          "isVatRegistered": {
            "type": "boolean",
            "description": "Whether the practice is registered for VAT"
          },
          "companyNumber": {
            "type": "string",
            "description": "Companies House registration number (if the practice is a limited company)",
            "nullable": true
          },
          "logoUrl": {
            "type": "string",
            "description": "URL to the practice logo image (from image assets)",
            "nullable": true
          },
          "address": {
            "type": "string",
            "description": "Practice physical/postal address",
            "nullable": true
          },
          "website": {
            "type": "string",
            "description": "Practice website URL",
            "nullable": true
          },
          "email": {
            "type": "string",
            "description": "Practice email address for general inquiries",
            "format": "email",
            "nullable": true
          },
          "mobile": {
            "type": "string",
            "description": "Practice mobile phone number",
            "nullable": true
          },
          "telephone": {
            "type": "string",
            "description": "Practice landline telephone number",
            "nullable": true
          },
          "professionalBody": {
            "$ref": "#/components/schemas/ProfessionalBody"
          },
          "professionalBodyName": {
            "type": "string",
            "description": "Full name of the professional body (e.g. \"Institute of Chartered Accountants in England and Wales\"). Derived from ProfessionalBody.",
            "nullable": true,
            "readOnly": true
          },
          "professionalBodyWebsite": {
            "type": "string",
            "description": "Public website URL for the professional body (e.g. \"https://www.icaew.com\"). Derived from ProfessionalBody.",
            "nullable": true,
            "readOnly": true
          },
          "hmrc": {
            "$ref": "#/components/schemas/PracticeHmrcDetailsDto"
          },
          "logo": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "logoCode": {
            "type": "string",
            "description": "Code of the image asset to use as the practice logo",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request to update practice/firm details"
      },
      "UpdateProfessionalClearanceLetterSettingsRequest": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "Whether professional clearance letter functionality is enabled for this tenant"
          },
          "emailContentBlockCode": {
            "type": "string",
            "description": "Code of the content block to use for email body",
            "nullable": true
          },
          "ccRecipientConfig": {
            "$ref": "#/components/schemas/EmailRecipientConfig"
          }
        },
        "additionalProperties": false,
        "description": "Request to update professional clearance letter settings for the tenant"
      },
      "UpdateProfessionalClearanceRequestItemRequest": {
        "type": "object",
        "properties": {
          "request": {
            "type": "string",
            "description": "The request text",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "The sort order for displaying the requests",
            "format": "int32"
          },
          "global": {
            "type": "boolean",
            "description": "If true, this item will be included for all clients regardless of the services they have"
          }
        },
        "additionalProperties": false,
        "description": "DTO for updating a professional clearance request item"
      },
      "UpdateRecurringTaskItemRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The name of the recurring task",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "The description of the recurring task",
            "nullable": true
          },
          "timeEstimateMinutes": {
            "type": "integer",
            "description": "The estimated time to complete the task, in whole minutes.",
            "format": "int32",
            "nullable": true
          },
          "assignedUserCode": {
            "type": "string",
            "description": "Code of the user to assign tasks to (only used if AssignmentType is SpecificUser)",
            "nullable": true
          },
          "assignedTeamCode": {
            "type": "string",
            "description": "Code of the team to assign tasks to (optional, independent of AssignmentType)",
            "nullable": true
          },
          "billableServiceCode": {
            "type": "string",
            "description": "Code of the billable service (only used if AssignmentType is ClientServiceManager)",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "Sort order for displaying recurring tasks",
            "format": "int32",
            "nullable": true
          },
          "active": {
            "type": "boolean",
            "description": "Whether this recurring task is active and will generate new tasks"
          },
          "taskStartConfig": {
            "$ref": "#/components/schemas/TaskStartConfigDto"
          },
          "dueDateConfig": {
            "$ref": "#/components/schemas/DueDateConfigDto"
          },
          "statutoryDateConfig": {
            "$ref": "#/components/schemas/StatutoryDateConfigDto"
          },
          "recurrence": {
            "$ref": "#/components/schemas/RecurrenceConfigDto"
          },
          "taskDateBasis": {
            "$ref": "#/components/schemas/TaskDateBasis"
          },
          "startHolidayAdjustment": {
            "$ref": "#/components/schemas/HolidayAdjustment"
          },
          "dueHolidayAdjustment": {
            "$ref": "#/components/schemas/HolidayAdjustment"
          },
          "assignmentType": {
            "$ref": "#/components/schemas/AssignmentType"
          },
          "workflowCode": {
            "type": "string",
            "description": "Code of the workflow template to apply to generated tasks",
            "nullable": true
          },
          "categoryCode": {
            "type": "string",
            "description": "Code of the category to apply to generated tasks (optional)",
            "nullable": true
          },
          "clientAssociationType": {
            "$ref": "#/components/schemas/ClientAssociationType"
          },
          "vatReportingPeriod": {
            "$ref": "#/components/schemas/VatReportingPeriod"
          },
          "checklist": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChecklistItemDto"
            },
            "description": "Checklist items for this recurring task template",
            "nullable": true
          },
          "taskNameTemplate": {
            "maxLength": 500,
            "type": "string",
            "description": "Optional template for naming tasks created from this recurring task.\nSupports {{ token }} placeholders (e.g. \"VAT Return - {{ ClientName }} - {{ Quarter }} {{ Year }}\").\nWhen null or empty, tasks use the recurring task's Name.\nAvailable tokens can be retrieved from the GET /metadata/task-name-tokens endpoint.\nUnrecognised tokens are left as-is in generated task names.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "UpdateRevenueRangeRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The display name of the revenue range (e.g., \"£30k - £70k\")",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "The sort order for displaying revenue ranges",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "DTO for updating a revenue range"
      },
      "UpdateSalesPipelineSettingsRequest": {
        "type": "object",
        "properties": {
          "isEnabled": {
            "type": "boolean",
            "description": "Whether the Sales Pipeline feature is enabled for this tenant. Enabling it reveals the\npipeline UI, runs pipeline automations for Active Prospects, and includes Active Prospects\nin the tenant's billable client count."
          }
        },
        "additionalProperties": false,
        "description": "Request to update the tenant's Sales Pipeline settings."
      },
      "UpdateSavedClientFilterRequest": {
        "required": [
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "maxLength": 200,
            "minLength": 1,
            "type": "string",
            "description": "User-friendly name for this saved filter (e.g., \"Active Limited Companies\", \"My Managed Clients\")"
          },
          "description": {
            "maxLength": 1000,
            "type": "string",
            "description": "Optional description providing more details about this filter's purpose",
            "nullable": true
          },
          "includeInMenu": {
            "type": "boolean",
            "description": "Whether this filter should be included in the current user's menu/quick access list.\nThis is a per-user preference — it does not affect other users of a shared filter."
          },
          "isShared": {
            "type": "boolean",
            "description": "Whether this filter is shared with all users in the tenant. Shared filters are\nvisible (read-only) to everyone; only the owner can modify or delete them."
          },
          "managerCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by manager code(s)",
            "nullable": true
          },
          "partnerCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by partner code(s)",
            "nullable": true
          },
          "associateCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by associate code(s)",
            "nullable": true
          },
          "statuses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientStatus"
            },
            "description": "Filter by client status(es)",
            "nullable": true
          },
          "types": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientType"
            },
            "description": "Filter by client type(s)",
            "nullable": true
          },
          "serviceCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by billable service code(s)",
            "nullable": true
          },
          "packageCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by service package code(s)",
            "nullable": true
          },
          "teamCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by team code(s)",
            "nullable": true
          },
          "serviceStageCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by service stage composite codes (format: \"serviceCode:stageCode\")",
            "nullable": true
          },
          "defaultSortField": {
            "$ref": "#/components/schemas/ClientSortField"
          },
          "defaultSortDesc": {
            "type": "boolean",
            "description": "Sort in descending order (true) or ascending order (false)",
            "nullable": true
          },
          "iconName": {
            "maxLength": 100,
            "type": "string",
            "description": "Optional Lucide icon name for visual identification (e.g., \"Calendar\", \"Users\", \"Star\")",
            "nullable": true
          },
          "color": {
            "maxLength": 7,
            "type": "string",
            "description": "Optional hex color for visual identification (e.g., \"#FF5733\")",
            "nullable": true
          },
          "columnConfigJson": {
            "type": "string",
            "description": "Optional JSON column configuration for the saved view.\nWhen set, overrides the user's default client column preferences.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request model for updating an existing saved client filter"
      },
      "UpdateSavedTaskFilterRequest": {
        "required": [
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "maxLength": 200,
            "minLength": 1,
            "type": "string",
            "description": "User-friendly name for this saved filter (e.g., \"My Overdue Tasks\", \"Client ABC Tasks\")"
          },
          "description": {
            "maxLength": 1000,
            "type": "string",
            "description": "Optional description providing more details about this filter's purpose",
            "nullable": true
          },
          "includeInMenu": {
            "type": "boolean",
            "description": "Whether this filter should be included in the current user's menu/quick access list.\nThis is a per-user preference — it does not affect other users of a shared filter."
          },
          "isShared": {
            "type": "boolean",
            "description": "Whether this filter is shared with all users in the tenant. Shared filters are\nvisible (read-only) to everyone; only the owner can modify or delete them."
          },
          "dateRange": {
            "$ref": "#/components/schemas/PresetDateRange"
          },
          "startDate": {
            "type": "string",
            "description": "Custom start date (only used when DateRange = CustomDateRange)",
            "format": "date",
            "nullable": true
          },
          "endDate": {
            "type": "string",
            "description": "Custom end date (only used when DateRange = CustomDateRange)",
            "format": "date",
            "nullable": true
          },
          "dateBasis": {
            "$ref": "#/components/schemas/TaskDateBasis"
          },
          "clientCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by client code(s)",
            "nullable": true
          },
          "userCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by user code(s)",
            "nullable": true
          },
          "recurringTaskCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by recurring task code(s)",
            "nullable": true
          },
          "categoryCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by category code(s)",
            "nullable": true
          },
          "teamCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Filter by team code(s)",
            "nullable": true
          },
          "statuses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TaskItemStatus"
            },
            "description": "Filter by task status(es)",
            "nullable": true
          },
          "isOverdue": {
            "type": "boolean",
            "description": "Filter to only overdue tasks",
            "nullable": true
          },
          "isUnassigned": {
            "type": "boolean",
            "description": "Include tasks with no assigned user. Can be combined with UserCodes to show\ntasks that are either unassigned OR assigned to specific users.",
            "nullable": true
          },
          "includeProjected": {
            "type": "boolean",
            "description": "Include projected (virtual) tasks in the results"
          },
          "includeWorkflowSteps": {
            "type": "boolean",
            "description": "Include workflow steps in the results (Agenda mode)"
          },
          "defaultSortField": {
            "$ref": "#/components/schemas/TaskItemSortField"
          },
          "defaultSortDesc": {
            "type": "boolean",
            "description": "Sort in descending order (true) or ascending order (false)",
            "nullable": true
          },
          "iconName": {
            "maxLength": 100,
            "type": "string",
            "description": "Optional Lucide icon name for visual identification (e.g., \"Calendar\", \"Users\", \"Star\")",
            "nullable": true
          },
          "color": {
            "maxLength": 7,
            "type": "string",
            "description": "Optional hex color for visual identification (e.g., \"#FF5733\")",
            "nullable": true
          },
          "columnConfigJson": {
            "type": "string",
            "description": "Optional JSON column configuration for the saved view.\nWhen set, overrides the user's default task column preferences.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request model for updating an existing saved task filter"
      },
      "UpdateServicePackageRequest": {
        "required": [
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "minLength": 1,
            "type": "string",
            "description": "The name of the service package"
          },
          "description": {
            "type": "string",
            "description": "Description of what this package includes",
            "nullable": true
          },
          "isArchived": {
            "type": "boolean",
            "description": "Whether this package is archived (inactive)"
          },
          "usePackagePricing": {
            "type": "boolean",
            "description": "Whether this package uses a single package-level price instead of summing individual item prices"
          },
          "packagePrice": {
            "type": "number",
            "description": "The flat price for the entire package. Required when UsePackagePricing is true.",
            "format": "double",
            "nullable": true
          },
          "packageBillingFrequency": {
            "$ref": "#/components/schemas/BillingFrequency"
          },
          "packageSetupFee": {
            "minimum": 0,
            "type": "number",
            "description": "Optional one-off setup fee for the package, billed once when the package is first invoiced.\nOnly used when UsePackagePricing is true. Null means no setup fee.",
            "format": "double",
            "nullable": true
          },
          "proposalContentCode": {
            "type": "string",
            "description": "The code of the proposal content block. Only used when UsePackagePricing is true.\nWhen set, overrides the individual content blocks defined on each service in the package.\nWhen null, proposals fall back to each service's own proposal content block.",
            "nullable": true
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CreateServicePackageItemRequest"
            },
            "description": "The services to include in this package",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for updating a service package"
      },
      "UpdateSubscriptionBillingRequest": {
        "type": "object",
        "properties": {
          "additionalInvoiceRecipients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InvoiceRecipient"
            },
            "description": "Additional email recipients for invoices.",
            "nullable": true
          },
          "billingAddress": {
            "$ref": "#/components/schemas/BillingAddress"
          }
        },
        "additionalProperties": false,
        "description": "Request to update billing address and invoice recipients.\nName and billing contact are not user-settable."
      },
      "UpdateTaskCategoryRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The display name of the task category",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "The sort order for displaying task categories",
            "format": "int32"
          },
          "color": {
            "type": "string",
            "description": "The color associated with this task category",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "DTO for updating a task category"
      },
      "UpdateTaskFocusConfigItemRequest": {
        "type": "object",
        "properties": {
          "savedTaskFilterCode": {
            "type": "string",
            "description": "The code of the saved task filter to reference",
            "nullable": true
          },
          "label": {
            "type": "string",
            "description": "Optional custom label for this item in the focus panel",
            "nullable": true
          },
          "sortOrder": {
            "type": "integer",
            "description": "Sort order for display in the focus panel",
            "format": "int32"
          },
          "color": {
            "type": "string",
            "description": "Optional color for visual styling in the focus panel",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for a single item in the task focus panel configuration"
      },
      "UpdateTaskFocusConfigRequest": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UpdateTaskFocusConfigItemRequest"
            },
            "description": "The saved task filter items to display in the focus panel",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for upserting a user's task focus panel configuration"
      },
      "UpdateTaskItemNoteRequest": {
        "required": [
          "date",
          "noteFromUserCode",
          "text"
        ],
        "type": "object",
        "properties": {
          "text": {
            "minLength": 1,
            "type": "string",
            "description": "The text content of the note"
          },
          "date": {
            "type": "string",
            "description": "The date/time the note was created",
            "format": "date-time"
          },
          "noteFromUserCode": {
            "minLength": 1,
            "type": "string",
            "description": "The code of the user who authored this note"
          },
          "pinnedLevel": {
            "type": "integer",
            "description": "The pinned level for ordering pinned notes",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for updating a task item note"
      },
      "UpdateTaskItemRequest": {
        "required": [
          "dueDate",
          "name",
          "startDate",
          "status"
        ],
        "type": "object",
        "properties": {
          "name": {
            "minLength": 1,
            "type": "string",
            "description": "The name of the task"
          },
          "description": {
            "type": "string",
            "description": "The description of the task",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/TaskItemStatus"
          },
          "timeEstimateMinutes": {
            "type": "integer",
            "description": "The estimated time to complete the task, in whole minutes.",
            "format": "int32",
            "nullable": true
          },
          "startDate": {
            "type": "string",
            "description": "When the task starts",
            "format": "date"
          },
          "dueDate": {
            "type": "string",
            "description": "When the task is due",
            "format": "date"
          },
          "statutoryDueDate": {
            "type": "string",
            "description": "The statutory due date for compliance tasks (if applicable)",
            "format": "date",
            "nullable": true
          },
          "clientCodes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The codes of the clients this task is associated with (optional)",
            "nullable": true
          },
          "primaryClientCode": {
            "type": "string",
            "description": "The code of the primary client for this task (optional)",
            "nullable": true
          },
          "assignedUserCode": {
            "type": "string",
            "description": "The code of the user to assign the task to (optional)",
            "nullable": true
          },
          "assignedTeamCode": {
            "type": "string",
            "description": "The code of the team to assign the task to (optional)",
            "nullable": true
          },
          "clientBillableServiceCode": {
            "type": "string",
            "description": "The code of the client billable service this task relates to (optional)",
            "nullable": true
          },
          "categoryCode": {
            "type": "string",
            "description": "The code of the category for this task (optional)",
            "nullable": true
          },
          "checklist": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChecklistItemDto"
            },
            "description": "Checklist items for this task",
            "nullable": true
          },
          "recurringTaskCode": {
            "type": "string",
            "description": "The code of the recurring task this task is associated with (optional)",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request model for updating an existing task"
      },
      "UpdateTeamRequest": {
        "required": [
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "maxLength": 200,
            "minLength": 1,
            "type": "string",
            "description": "The display name of the team"
          },
          "description": {
            "maxLength": 500,
            "type": "string",
            "description": "Optional description of the team's purpose",
            "nullable": true
          },
          "iconName": {
            "maxLength": 100,
            "type": "string",
            "description": "Optional Lucide icon name for visual identification",
            "nullable": true
          },
          "color": {
            "maxLength": 7,
            "type": "string",
            "description": "Optional hex color for visual identification",
            "nullable": true
          },
          "canBeAssignedToTasks": {
            "type": "boolean",
            "description": "Whether this team can be assigned to tasks"
          },
          "canBeAssignedToClients": {
            "type": "boolean",
            "description": "Whether this team can be assigned to clients"
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for updating a team"
      },
      "UpdateTenantHolidayRequest": {
        "type": "object",
        "properties": {
          "date": {
            "type": "string",
            "description": "The date of the holiday (format: yyyy-MM-dd)",
            "format": "date"
          },
          "name": {
            "type": "string",
            "description": "Name of the holiday (e.g., \"Company Anniversary\", \"Office Closure\")",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request to update a tenant-specific holiday"
      },
      "UpdateTenantUserRequest": {
        "type": "object",
        "properties": {
          "roleType": {
            "$ref": "#/components/schemas/RoleType"
          },
          "roleId": {
            "type": "integer",
            "description": "The ID of the custom role (only used if RoleType is Custom)",
            "format": "int32",
            "nullable": true
          },
          "systemRoleType": {
            "$ref": "#/components/schemas/SystemRole"
          },
          "isClientManager": {
            "type": "boolean",
            "description": "Whether the user is a client manager within the tenant"
          },
          "isPartner": {
            "type": "boolean",
            "description": "Whether the user is a partner within the tenant"
          },
          "isAssociate": {
            "type": "boolean",
            "description": "Whether the user is an associate within the tenant"
          },
          "isRestrictedToTeamClients": {
            "type": "boolean",
            "description": "Whether the user can only see clients belonging to their teams"
          },
          "isRestrictedToAssignedClients": {
            "type": "boolean",
            "description": "Whether the user can only see clients where they are Manager, Partner, or Associate"
          },
          "hourlyRate": {
            "maximum": 100000,
            "minimum": 0,
            "type": "number",
            "description": "Charge-out rate per hour for time tracking.\nFalls back to the practice default rate when null.",
            "format": "double",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "DTO for Updating a user within a tenant. Does not include email as it cannot be changed.\nFirstName/LastName are managed via User updates and synced to TenantUser automatically."
      },
      "UpdateThirdPartyConnectionRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Display name for the connection",
            "nullable": true
          },
          "redirectUrl": {
            "type": "string",
            "description": "URL to redirect the user to after OAuth flow completes. \nIf you use [code] in the url then we'll replace it with the Code of this ThirdPartyConnection.\nThis solves the problem of not knowing the code at creation time.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request for updating an existing ThirdPartyConnection"
      },
      "UpdateTimeEntryRequest": {
        "required": [
          "entryDate",
          "userCode"
        ],
        "type": "object",
        "properties": {
          "userCode": {
            "minLength": 1,
            "type": "string",
            "description": "The code of the team member who did the work"
          },
          "entryDate": {
            "type": "string",
            "description": "The day the work was done (format: yyyy-MM-dd)",
            "format": "date"
          },
          "durationMinutes": {
            "maximum": 1440,
            "minimum": 1,
            "type": "integer",
            "description": "How long the work took, in minutes",
            "format": "int32"
          },
          "startTime": {
            "type": "string",
            "description": "When the work started (UTC) — optional, set by timer-logged entries",
            "format": "date-time",
            "nullable": true
          },
          "endTime": {
            "type": "string",
            "description": "When the work ended (UTC) — optional, set by timer-logged entries",
            "format": "date-time",
            "nullable": true
          },
          "description": {
            "maxLength": 1000,
            "type": "string",
            "description": "What the time was spent on",
            "nullable": true
          },
          "clientCode": {
            "type": "string",
            "description": "The code of the client the time relates to (optional unless the practice requires linking)",
            "nullable": true
          },
          "taskItemCode": {
            "type": "string",
            "description": "The code of the task the time relates to (optional unless the practice requires linking)",
            "nullable": true
          },
          "workflowGroupNumber": {
            "type": "integer",
            "description": "The group number of the workflow step the time relates to (optional; requires\nTaskItemCode and WorkflowStepNumber). Omit both numbers to unlink the step.",
            "format": "int32",
            "nullable": true
          },
          "workflowStepNumber": {
            "type": "integer",
            "description": "The step number of the workflow step the time relates to (optional; requires\nTaskItemCode and WorkflowGroupNumber). Omit both numbers to unlink the step.",
            "format": "int32",
            "nullable": true
          },
          "blocks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TimerBlockDto"
            },
            "description": "The edited work blocks, for block-sourced entries. When provided, StartTime,\nEndTime and DurationMinutes are derived from the blocks and any supplied\nvalues are ignored; when omitted the entry's existing blocks are kept.\nEach block needs either a start and end time or a duration in minutes.",
            "nullable": true
          },
          "isBillable": {
            "type": "boolean",
            "description": "Whether this time can be billed to the client"
          },
          "hourlyRate": {
            "maximum": 100000,
            "minimum": 0,
            "type": "number",
            "description": "Charge-out rate per hour",
            "format": "double",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request to update a time entry (full replacement)"
      },
      "UpdateTimeRecordingSettingsRequest": {
        "type": "object",
        "properties": {
          "timeTrackingEnabled": {
            "type": "boolean",
            "description": "Whether time tracking is enabled for this tenant"
          },
          "requireClientOrTask": {
            "type": "boolean",
            "description": "When true, every time entry must be linked to a client or a task"
          },
          "billableByDefault": {
            "type": "boolean",
            "description": "When true, new time entries and timers start as billable"
          },
          "defaultHourlyRate": {
            "maximum": 100000,
            "minimum": 0,
            "type": "number",
            "description": "Default charge-out rate per hour for billable time entries,\nused when the team member has no rate of their own",
            "format": "double",
            "nullable": true
          },
          "billingLineMode": {
            "$ref": "#/components/schemas/TimeBillingLineMode"
          },
          "autoTimerEnabled": {
            "type": "boolean",
            "description": "When true, starting a workflow step (or a task with no workflow) starts a timer\nfor the acting user linked to it, and completing or skipping it stops the linked\ntimer and logs the time"
          }
        },
        "additionalProperties": false,
        "description": "Request to update time recording settings for the tenant"
      },
      "UpdateUserProfileRequest": {
        "type": "object",
        "properties": {
          "firstName": {
            "type": "string",
            "description": "The user's first name",
            "nullable": true
          },
          "lastName": {
            "type": "string",
            "description": "The user's last name",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for updating user profile information (name only)"
      },
      "UpdateWorkflowRequest": {
        "required": [
          "groups",
          "name"
        ],
        "type": "object",
        "properties": {
          "name": {
            "maxLength": 100,
            "minLength": 0,
            "type": "string",
            "description": "The name of the workflow"
          },
          "description": {
            "type": "string",
            "description": "Optional description explaining the workflow's purpose",
            "nullable": true
          },
          "groups": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowGroupDto"
            },
            "description": "The workflow groups containing steps"
          },
          "deadlineRelativeTo": {
            "$ref": "#/components/schemas/DeadlineReferenceType"
          }
        },
        "additionalProperties": false,
        "description": "Request to update an existing workflow"
      },
      "UpdateWorkflowStepRequest": {
        "type": "object",
        "properties": {
          "status": {
            "$ref": "#/components/schemas/TaskItemStatus"
          },
          "blockedReason": {
            "maxLength": 500,
            "type": "string",
            "description": "The reason the step is blocked (optional). Only used when setting status to \"Blocked\".",
            "nullable": true
          },
          "assignedUserCode": {
            "maxLength": 50,
            "type": "string",
            "description": "The user code to assign this step to (optional).\nMust be a valid user code for an active user in the tenant.\nIf null, the assignment will not be changed.",
            "nullable": true
          },
          "assignedTeamCode": {
            "maxLength": 100,
            "type": "string",
            "description": "The team code to assign this step to (optional, independent of user assignment).\nIf null, the team assignment will not be changed.",
            "nullable": true
          },
          "emailStepConfiguration": {
            "$ref": "#/components/schemas/EmailStepConfigDto"
          },
          "documentRequestStepConfiguration": {
            "$ref": "#/components/schemas/DocumentRequestStepConfigDto"
          },
          "clientConfirmationStepConfiguration": {
            "$ref": "#/components/schemas/ClientConfirmationStepConfigDto"
          },
          "checklist": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChecklistItemDto"
            },
            "description": "Checklist items for this workflow step. Replaces all existing checklist items when provided.",
            "nullable": true
          },
          "hasUpdates": {
            "type": "boolean",
            "description": "Validates that at least one property is being updated",
            "readOnly": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for updating workflow step properties.\nSupports updating status, assignment, and step-type configuration.\nAt least one property must be provided.\n            \nAPI Usage:\n- PUT /api/tenants/{tenant}/tasks/{taskCode}/workflow/steps/{stepId}\n- Supports updating multiple fields at once or individual fields\n- Validates that changes are appropriate and permissions are met\n            \nExample Usage:\n```\nPUT /api/tenants/acme/tasks/TASK-001/workflow/steps/123\n{\n    \"status\": \"Completed\",\n    \"assignedUserCode\": \"john.doe\"\n}\n```"
      },
      "UpdateWorkingDaySettingsRequest": {
        "type": "object",
        "properties": {
          "defaultHolidayAdjustment": {
            "$ref": "#/components/schemas/HolidayAdjustment"
          },
          "bankHolidayRegion": {
            "$ref": "#/components/schemas/BankHolidayRegion"
          }
        },
        "additionalProperties": false,
        "description": "Request to update working day settings for the tenant"
      },
      "UploadEngagementPdfRequest": {
        "required": [
          "pdfContent"
        ],
        "type": "object",
        "properties": {
          "pdfContent": {
            "minLength": 1,
            "type": "string",
            "description": "Base64-encoded PDF content.\nExample: \"JVBERi0xLjQKJeLjz9MNCjEgMCBvYmoKPDwKL1R5cGUgL0NhdGFsb2cK...\""
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for uploading PDF documents to an engagement"
      },
      "UpsertBaseFolderRequest": {
        "required": [
          "containerId",
          "displayPath"
        ],
        "type": "object",
        "properties": {
          "containerId": {
            "minLength": 1,
            "type": "string",
            "description": "Provider-specific identifier for the folder/container.\n- Google Drive: The folder ID"
          },
          "driveId": {
            "type": "string",
            "description": "Provider-specific drive identifier. Null when not applicable.\n- Google Drive: The Shared Drive ID if using a Shared Drive; null for \"My Drive\"",
            "nullable": true
          },
          "siteId": {
            "type": "string",
            "description": "Provider-specific site identifier. Null when not applicable.\n- Google Drive: Not used",
            "nullable": true
          },
          "displayPath": {
            "minLength": 1,
            "type": "string",
            "description": "Human-readable path for display in the UI only.\ne.g., \"My Drive/Sodium/Clients\""
          },
          "externalUrl": {
            "type": "string",
            "description": "URL to open this folder in the provider's web UI",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for upserting the base folder for a connection"
      },
      "UpsertServiceMappingRequest": {
        "required": [
          "billableServiceCode",
          "externalServiceId"
        ],
        "type": "object",
        "properties": {
          "externalServiceId": {
            "minLength": 1,
            "type": "string",
            "description": "The external platform's service template ID (e.g., Socket's availableProposalLineId)"
          },
          "externalServiceName": {
            "type": "string",
            "description": "The display name of the service on the external platform (cached for display)",
            "nullable": true
          },
          "billableServiceCode": {
            "minLength": 1,
            "type": "string",
            "description": "The Sodium BillableService code to map to"
          }
        },
        "additionalProperties": false,
        "description": "Request to map an external service template to a Sodium BillableService"
      },
      "UpsertUserViewPreferenceRequest": {
        "required": [
          "configJson"
        ],
        "type": "object",
        "properties": {
          "configJson": {
            "minLength": 1,
            "type": "string",
            "description": "The JSON configuration for this view"
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for creating or updating a user's view preference"
      },
      "UserBillingSummaryDto": {
        "type": "object",
        "properties": {
          "includedUserCount": {
            "type": "integer",
            "description": "Number of users included in the subscription at no extra charge",
            "format": "int32"
          },
          "additionalUserPricePence": {
            "type": "integer",
            "description": "Monthly price in pence for each user above IncludedUserCount. 0 = overage billing disabled.",
            "format": "int32"
          },
          "billableUserCount": {
            "type": "integer",
            "description": "Current number of users counting towards the allowance (Active and Invited)",
            "format": "int32"
          },
          "additionalUserCount": {
            "type": "integer",
            "description": "Number of users above the included allowance (0 when within the allowance)",
            "format": "int32"
          },
          "estimatedMonthlyChargePence": {
            "type": "integer",
            "description": "Estimated monthly charge in pence for the additional users\n(AdditionalUserCount x AdditionalUserPricePence)",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Summary of the tenant's per-user billing position: how many users are included\nin their subscription, how many they have, and what any additional users cost."
      },
      "UserProfileResponse": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The user's unique code",
            "nullable": true
          },
          "email": {
            "type": "string",
            "description": "The user's email address",
            "nullable": true
          },
          "firstName": {
            "type": "string",
            "description": "The user's first name",
            "nullable": true
          },
          "lastName": {
            "type": "string",
            "description": "The user's last name",
            "nullable": true
          },
          "fullName": {
            "type": "string",
            "description": "The user's full name",
            "nullable": true
          },
          "avatar": {
            "type": "string",
            "description": "URL to the user's avatar image",
            "nullable": true
          },
          "utm": {
            "$ref": "#/components/schemas/UtmInfoDto"
          }
        },
        "additionalProperties": false,
        "description": "Response DTO for user profile information"
      },
      "UserViewPreferenceDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Unique identifier within the tenant",
            "nullable": true
          },
          "viewKey": {
            "type": "string",
            "description": "The view this preference applies to (e.g. \"dashboard\")",
            "nullable": true
          },
          "configJson": {
            "type": "string",
            "description": "The JSON configuration for this view",
            "nullable": true
          },
          "createdDate": {
            "type": "string",
            "description": "When the preference was created",
            "format": "date-time"
          },
          "updatedDate": {
            "type": "string",
            "description": "When the preference was last updated",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response DTO for a user's view preference configuration"
      },
      "UtmInfoDto": {
        "type": "object",
        "properties": {
          "source": {
            "type": "string",
            "nullable": true
          },
          "medium": {
            "type": "string",
            "nullable": true
          },
          "term": {
            "type": "string",
            "nullable": true
          },
          "content": {
            "type": "string",
            "nullable": true
          },
          "campaign": {
            "type": "string",
            "nullable": true
          },
          "referer": {
            "type": "string",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "DTO containing UTM tracking information"
      },
      "ValidationProblemDetails": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "nullable": true
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "detail": {
            "type": "string",
            "nullable": true
          },
          "instance": {
            "type": "string",
            "nullable": true
          },
          "errors": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "nullable": true
          }
        },
        "additionalProperties": {}
      },
      "VatDetailsDto": {
        "type": "object",
        "properties": {
          "registered": {
            "type": "boolean",
            "description": "Indicates whether the business is registered for VAT"
          },
          "number": {
            "maxLength": 14,
            "type": "string",
            "description": "VAT registration number",
            "nullable": true
          },
          "registrationDate": {
            "type": "string",
            "description": "Date when the business registered for VAT",
            "format": "date-time",
            "nullable": true
          },
          "scheme": {
            "$ref": "#/components/schemas/VatScheme"
          },
          "reportingPeriod": {
            "$ref": "#/components/schemas/VatReportingPeriod"
          }
        },
        "additionalProperties": false,
        "description": "VAT registration and scheme details for a business"
      },
      "VatPeriodTokens": {
        "type": "object",
        "properties": {
          "period": {
            "type": "string",
            "description": "Human label for the period (e.g. \"May 2026\" or \"Apr-Jun 2026\").",
            "nullable": true
          },
          "periodStart": {
            "type": "string",
            "description": "First day of the VAT return period being filed.",
            "format": "date",
            "nullable": true
          },
          "periodEnd": {
            "type": "string",
            "description": "Last day of the VAT return period being filed.",
            "format": "date",
            "nullable": true
          },
          "submissionDeadline": {
            "type": "string",
            "description": "HMRC submission deadline - one calendar month and seven days after the period end.",
            "format": "date",
            "nullable": true
          },
          "previous": {
            "$ref": "#/components/schemas/VatPeriodTokens"
          },
          "next": {
            "$ref": "#/components/schemas/VatPeriodTokens"
          }
        },
        "additionalProperties": false,
        "description": "Computed VAT period tokens for the return the client is currently filing - the most recently\nclosed period whose submission deadline has not yet passed (falling through to the open period\nonce that deadline is behind us). Anchored on a supplied reference date, so an email generated\nfrom a task can resolve the return the task is for, independent of when the email is sent.\nUsage: {{ Vat.Period }}, {{ Vat.PeriodStart | formatDate: \"dd MMM yyyy\" }}, {{ Vat.SubmissionDeadline | formatDate: \"dd MMM yyyy\" }}.\nEmpty when the client is not VAT-registered, has no reporting period, or is on the Annual scheme."
      },
      "VatRate": {
        "enum": [
          "Standard",
          "Reduced",
          "Zero",
          "Exempt",
          "OutOfScope"
        ],
        "type": "string"
      },
      "VatReportingPeriod": {
        "enum": [
          "Monthly",
          "QuarterlyJanAprJulOct",
          "QuarterlyFebMayAugNov",
          "QuarterlyMarJunSepDec",
          "Annual"
        ],
        "type": "string"
      },
      "VatScheme": {
        "enum": [
          "Standard",
          "FlatRate",
          "CashAccounting",
          "AnnualAccounting",
          "MarginScheme"
        ],
        "type": "string"
      },
      "VerificationResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean",
            "description": "Whether the operation was successful"
          },
          "message": {
            "type": "string",
            "description": "Message describing the result",
            "nullable": true
          },
          "errorCode": {
            "type": "string",
            "description": "Error code for client handling (if failed)",
            "nullable": true
          },
          "userCode": {
            "type": "string",
            "description": "User code (if applicable)",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response DTO for email verification operations"
      },
      "VerifyEmailRequest": {
        "required": [
          "verificationKey"
        ],
        "type": "object",
        "properties": {
          "verificationKey": {
            "type": "string",
            "description": "The verification key from the email link",
            "format": "uuid"
          }
        },
        "additionalProperties": false,
        "description": "Request DTO for email verification"
      },
      "WeekDayPatternDto": {
        "type": "object",
        "properties": {
          "position": {
            "$ref": "#/components/schemas/MonthDayType"
          },
          "day": {
            "$ref": "#/components/schemas/WeekDayType"
          }
        },
        "additionalProperties": false,
        "description": "DTO for positional weekday patterns in recurring tasks.\nExample: { Position: \"First\", Day: \"Monday\" } for \"First Monday of the month\""
      },
      "WeekDayType": {
        "enum": [
          "Workday",
          "Monday",
          "Tuesday",
          "Wednesday",
          "Thursday",
          "Friday",
          "Saturday",
          "Sunday"
        ],
        "type": "string"
      },
      "WipAgeingReportDto": {
        "type": "object",
        "properties": {
          "summary": {
            "$ref": "#/components/schemas/WipAgeingSummaryDto"
          },
          "rows": {
            "$ref": "#/components/schemas/WipAgeingRowDtoPagedResult"
          },
          "generatedAt": {
            "type": "string",
            "description": "When the report was generated (UTC).",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "The WIP / Ageing report: a point-in-time snapshot of open work - what's sitting untouched,\nhow old it is, and where it's stuck."
      },
      "WipAgeingRowDto": {
        "type": "object",
        "properties": {
          "groupKind": {
            "$ref": "#/components/schemas/ReportGroupKind"
          },
          "groupCode": {
            "type": "string",
            "description": "Entity code, bucket key (\"0-7\"), status name, or current step name. Null for null buckets.",
            "nullable": true
          },
          "groupName": {
            "type": "string",
            "description": "Display name for the group.",
            "nullable": true
          },
          "currentStepType": {
            "$ref": "#/components/schemas/WorkflowStepType"
          },
          "count": {
            "type": "integer",
            "description": "Open tasks in this group.",
            "format": "int32"
          },
          "avgAgeDays": {
            "type": "number",
            "description": "Average age in days (planned start to today).",
            "format": "double"
          },
          "oldestAgeDays": {
            "type": "integer",
            "description": "Age of this group's oldest task in days.",
            "format": "int32"
          },
          "oldestTask": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "blockedCount": {
            "type": "integer",
            "description": "How many of this group's tasks are currently blocked.",
            "format": "int32"
          },
          "overdueCount": {
            "type": "integer",
            "description": "How many of this group's tasks are past their due date.",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "One row of the WIP / Ageing breakdown table."
      },
      "WipAgeingRowDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WipAgeingRowDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "WipAgeingSummaryDto": {
        "type": "object",
        "properties": {
          "openCount": {
            "type": "integer",
            "description": "Open tasks whose planned start date has arrived.",
            "format": "int32"
          },
          "notStartedCount": {
            "type": "integer",
            "description": "Cohort tasks not yet started - work that should have begun but hasn't been touched.",
            "format": "int32"
          },
          "blockedCount": {
            "type": "integer",
            "description": "Cohort tasks currently blocked.",
            "format": "int32"
          },
          "overdueCount": {
            "type": "integer",
            "description": "Cohort tasks past their due date.",
            "format": "int32"
          },
          "avgAgeDays": {
            "type": "number",
            "description": "Average age in days (planned start to today). Null when the cohort is empty.",
            "format": "double",
            "nullable": true
          },
          "oldestAgeDays": {
            "type": "integer",
            "description": "Age of the oldest open task in days. Null when the cohort is empty.",
            "format": "int32",
            "nullable": true
          },
          "oldestTask": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          }
        },
        "additionalProperties": false,
        "description": "Headline KPIs for the WIP / Ageing report."
      },
      "WorkflowDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Stable identifier. For library-shipped items this is the library code; for tenant-imported\nitems this is the tenant entity's own code.",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name shown to users in lists, dialogs, and the import browser.",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Optional human-readable summary of what this entity is for.",
            "nullable": true
          },
          "libraryCode": {
            "type": "string",
            "description": "The Code of the library template this entity was imported from, or null if the entity\nis not from the library. Read-only — cannot be changed once set. Example: \"vat_returns\".",
            "nullable": true
          },
          "libraryStatus": {
            "$ref": "#/components/schemas/LibraryStatus"
          },
          "isImported": {
            "type": "boolean",
            "description": "True if the tenant has already imported this library item."
          },
          "deprecated": {
            "type": "boolean",
            "description": "True if this library item has been retired. Deprecated items are hidden from the import\nbrowser (so new tasks cannot be created from them) but remain available for revert-to-library\non existing imports."
          },
          "deadlineRelativeTo": {
            "$ref": "#/components/schemas/DeadlineReferenceType"
          },
          "groupCount": {
            "type": "integer",
            "description": "Total number of groups in this workflow",
            "format": "int32"
          },
          "stepCount": {
            "type": "integer",
            "description": "Total number of steps across all groups in this workflow",
            "format": "int32"
          },
          "groups": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowGroupDto"
            },
            "description": "The workflow groups containing steps",
            "nullable": true
          },
          "hasAutoExecutingStepsWithNoDependencies": {
            "type": "boolean",
            "description": "Whether this workflow contains any auto-executing steps with no dependencies.\nThese steps will execute automatically when the workflow is applied to a task."
          },
          "requiresClient": {
            "type": "boolean",
            "description": "Whether this workflow requires a client to be associated with the task.\nTrue if any email step uses client tokens in content or sends to client contact recipients."
          }
        },
        "additionalProperties": false,
        "description": "DTO for workflow templates, exposing only codes and structured data (never DB IDs)."
      },
      "WorkflowDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "WorkflowGroupDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The name of the workflow group",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "The description of the workflow group",
            "nullable": true
          },
          "deadlineIntervalValue": {
            "type": "integer",
            "description": "The deadline interval value relative to the TaskItem's due date.\n            \nAPI Usage Examples:\n- Positive values: Days/weeks/months AFTER the task due date\n  * DeadlineIntervalValue = 1, DeadlineIntervalUnit = \"Week\" → 1 week after task deadline\n  * DeadlineIntervalValue = 5, DeadlineIntervalUnit = \"Day\" → 5 days after task deadline\n            \n- Negative values: Days/weeks/months BEFORE the task due date\n  * DeadlineIntervalValue = -2, DeadlineIntervalUnit = \"Day\" → 2 days before task deadline\n  * DeadlineIntervalValue = -1, DeadlineIntervalUnit = \"Week\" → 1 week before task deadline\n            \n- Zero: Same as the task due date\n  * DeadlineIntervalValue = 0, DeadlineIntervalUnit = \"Day\" → Same day as task deadline\n            \nWhen creating or updating workflows, this allows you to structure work phases:\nExample: Tax Return Workflow\n- \"Data Collection\" group: -14 days (2 weeks before tax deadline)\n- \"Preparation\" group: -7 days (1 week before tax deadline)\n- \"Review\" group: -1 day (1 day before tax deadline)\n- \"Filing\" group: 0 days (same as tax deadline)",
            "format": "int32"
          },
          "deadlineIntervalUnit": {
            "$ref": "#/components/schemas/RecurrenceUnit"
          },
          "groupNumber": {
            "type": "integer",
            "description": "The group number that determines the display order and sequencing of this group within the workflow.\nGroups are displayed in ascending order by this number (1, 2, 3, etc.).",
            "format": "int32"
          },
          "condition": {
            "$ref": "#/components/schemas/ConditionDto"
          },
          "clientTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientType"
            },
            "description": "The types of clients this group is applicable to.\nAn empty list means the group applies to all client types.",
            "nullable": true
          },
          "steps": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowStepDto"
            },
            "description": "The workflow steps contained within this group.\nAll steps inherit the group's calculated deadline for planning and prioritization.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "DTO for workflow groups within a workflow.\n            \nWorkflow Group Deadlines:\nGroups define deadlines relative to the TaskItem's due date using DeadlineIntervalValue and DeadlineIntervalUnit.\nWhen a workflow is assigned to a task, each group's deadline is calculated as:\nGroup Deadline = TaskItem.DueDate + (DeadlineIntervalValue * DeadlineIntervalUnit)\n            \nAll workflow steps within a group inherit the group's calculated deadline."
      },
      "WorkflowGroupProgressDto": {
        "type": "object",
        "properties": {
          "groupNumber": {
            "type": "integer",
            "description": "Sequential group number within the task (1, 2, 3, etc.).\nUsed for referencing the group in API calls and ordering display.",
            "format": "int32"
          },
          "groupName": {
            "type": "string",
            "description": "The name of the workflow group.\nUsed for section headers and group organization.",
            "nullable": true
          },
          "groupDescription": {
            "type": "string",
            "description": "The description of the workflow group.\nProvides context for the group's purpose.",
            "nullable": true
          },
          "groupDeadline": {
            "type": "string",
            "description": "The calculated deadline for this workflow group.\nThis is computed as TaskItem.DueDate + (DeadlineIntervalValue * DeadlineIntervalUnit)\nwhen the workflow is assigned to a task.\n            \nExample: If task is due March 15th and group has DeadlineIntervalValue = -3, DeadlineIntervalUnit = Day,\nthen GroupDeadline would be March 12th (3 days before task deadline).\n            \nThis deadline applies to all steps within this group.",
            "format": "date-time",
            "nullable": true
          },
          "steps": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowStepProgressDto"
            },
            "description": "The workflow steps belonging to this group.\nOrdered by step number for consistent display.",
            "nullable": true
          },
          "totalSteps": {
            "type": "integer",
            "description": "The number of steps in this group.\nUsed for group-level progress calculations.",
            "format": "int32"
          },
          "completedSteps": {
            "type": "integer",
            "description": "The number of completed steps in this group.\nUsed for group-level progress visualization.",
            "format": "int32"
          },
          "groupProgressPercentage": {
            "type": "number",
            "description": "The percentage of completion for this group (0-100).\nCalculated as (CompletedSteps / TotalSteps) * 100.\nUsed for group-level progress bars.",
            "format": "double"
          },
          "isOmitted": {
            "type": "boolean",
            "description": "Whether this group is omitted because its visibility condition is not met by the\ntask's primary client (set only when every step in the group is omitted)."
          },
          "omittedReason": {
            "type": "string",
            "description": "Human-readable explanation of why this group is omitted. Null when not omitted.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Represents a workflow group with its associated step progress.\nUsed for organizing workflow steps into logical groups for display.\n            \nAPI Usage:\n- Part of TaskWorkflowProgressDto for grouped step display\n- Helps organize large workflows into manageable sections\n- Provides group-level progress statistics and deadline information"
      },
      "WorkflowOccurrenceDto": {
        "type": "object",
        "properties": {
          "task": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "client": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "completedDate": {
            "type": "string",
            "description": "When the task completed (UTC).",
            "format": "date-time"
          },
          "totalElapsedDays": {
            "type": "number",
            "description": "Days from the task's actual start (fallback planned start) to completion.",
            "format": "double"
          },
          "clientWaitDays": {
            "type": "number",
            "description": "Days of the step chain spent waiting on the client.",
            "format": "double"
          },
          "internalDays": {
            "type": "number",
            "description": "Days of the step chain spent on practice-side steps.",
            "format": "double"
          }
        },
        "additionalProperties": false,
        "description": "One occurrence (task) of the workflow: its total elapsed time and the client-wait vs\ninternal split - \"show me the ten slowest VAT-return runs this quarter\"."
      },
      "WorkflowOccurrenceDtoPagedResult": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowOccurrenceDto"
            },
            "nullable": true
          },
          "totalCount": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "offset": {
            "type": "integer",
            "format": "int32"
          },
          "limit": {
            "type": "integer",
            "format": "int32"
          },
          "hasMore": {
            "type": "boolean"
          }
        },
        "additionalProperties": false
      },
      "WorkflowSortField": {
        "enum": [
          "Name",
          "GroupCount",
          "StepCount",
          "UpdatedDate"
        ],
        "type": "string"
      },
      "WorkflowStepAnalysisReportDto": {
        "type": "object",
        "properties": {
          "workflow": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "summary": {
            "$ref": "#/components/schemas/WorkflowStepAnalysisSummaryDto"
          },
          "steps": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowStepAnalysisStepDto"
            },
            "description": "Per-step duration distributions, in workflow order. The occurrence list is served\nseparately (paged) by the occurrences endpoint.",
            "nullable": true
          },
          "generatedAt": {
            "type": "string",
            "description": "When the report was generated (UTC).",
            "format": "date-time"
          }
        },
        "additionalProperties": false,
        "description": "The Workflow Step Analysis report: for one workflow template, where does the time go across\nevery occurrence (task) spawned from it - per-step duration distributions plus a worst-first\noccurrence list. Distributions over few occurrences are noise, so check the occurrence count."
      },
      "WorkflowStepAnalysisStepDto": {
        "type": "object",
        "properties": {
          "groupName": {
            "type": "string",
            "description": "The workflow group (section) the step belongs to - lets the UI divide the step table\ninto the same sections the workflow shows.",
            "nullable": true
          },
          "stepName": {
            "type": "string",
            "description": "The step name as snapshotted onto the tasks.",
            "nullable": true
          },
          "stepType": {
            "$ref": "#/components/schemas/WorkflowStepType"
          },
          "stage": {
            "$ref": "#/components/schemas/ClientBillableServiceStageDto"
          },
          "isClientWait": {
            "type": "boolean",
            "description": "True when the step completes on a client action - its elapsed time is client-wait time."
          },
          "count": {
            "type": "integer",
            "description": "Completed/skipped executions of this step in the cohort - the n behind the distribution.",
            "format": "int32"
          },
          "avgElapsedDays": {
            "type": "number",
            "description": "Average elapsed days (previous done step's completion to this step's completion, idle\ntime included).",
            "format": "double"
          },
          "medianElapsedDays": {
            "type": "number",
            "description": "Median elapsed days.",
            "format": "double"
          },
          "p90ElapsedDays": {
            "type": "number",
            "description": "90th-percentile elapsed days - the tail where the money is.",
            "format": "double"
          },
          "bestElapsedDays": {
            "type": "number",
            "description": "Fastest elapsed days in the cohort.",
            "format": "double"
          },
          "worstElapsedDays": {
            "type": "number",
            "description": "Slowest elapsed days in the cohort.",
            "format": "double"
          },
          "bestTask": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "worstTask": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "avgActiveDays": {
            "type": "number",
            "description": "Average active days (step started to completed - queued vs genuinely slow).\nNull when no execution recorded a start timestamp.",
            "format": "double",
            "nullable": true
          },
          "medianActiveDays": {
            "type": "number",
            "description": "Median active days.",
            "format": "double",
            "nullable": true
          },
          "skippedCount": {
            "type": "integer",
            "description": "Executions that were skipped rather than completed (their elapsed time stays in the averages).",
            "format": "int32"
          },
          "totalChases": {
            "type": "integer",
            "description": "Total chase messages sent for this step across the cohort.",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Per-step duration distribution across the workflow's occurrences. Steps are per-task\nsnapshots, so a step renamed in the template splits into separate rows - the per-step\ncount makes partial coverage visible."
      },
      "WorkflowStepAnalysisSummaryDto": {
        "type": "object",
        "properties": {
          "occurrenceCount": {
            "type": "integer",
            "description": "Occurrences (tasks spawned from the workflow) completed in the window - the n behind\nevery distribution in the report.",
            "format": "int32"
          },
          "avgTotalDays": {
            "type": "number",
            "description": "Average days from an occurrence's actual start to its completion. Null when the cohort is empty.",
            "format": "double",
            "nullable": true
          },
          "medianTotalDays": {
            "type": "number",
            "description": "Median days from start to completion.",
            "format": "double",
            "nullable": true
          },
          "avgClientWaitDays": {
            "type": "number",
            "description": "Average days per occurrence spent in client-wait steps (waiting on the client to act).",
            "format": "double",
            "nullable": true
          },
          "avgInternalDays": {
            "type": "number",
            "description": "Average days per occurrence spent in internal steps (practice-side time).",
            "format": "double",
            "nullable": true
          },
          "totalChases": {
            "type": "integer",
            "description": "Total chase messages sent across the cohort's steps.",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Headline KPIs for the Workflow Step Analysis report."
      },
      "WorkflowStepAssignmentType": {
        "enum": [
          "TaskOwner",
          "SpecificUser",
          "ClientManager",
          "ClientServiceManager",
          "ClientPartner",
          "ClientAssociate",
          "DoNotAssign"
        ],
        "type": "string"
      },
      "WorkflowStepClientDataDto": {
        "type": "object",
        "properties": {
          "fields": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowStepClientDataFieldDto"
            },
            "description": "The fields configured on this step with their current values and metadata.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Response containing the current client field values for an UpdateClientData workflow step."
      },
      "WorkflowStepClientDataFieldDto": {
        "type": "object",
        "properties": {
          "fieldType": {
            "$ref": "#/components/schemas/DataFormQuestionType"
          },
          "clientField": {
            "$ref": "#/components/schemas/ClientCsvTargetField"
          },
          "customFieldDefinitionCode": {
            "type": "string",
            "description": "The custom field definition code when FieldType is CustomField.",
            "nullable": true
          },
          "label": {
            "type": "string",
            "description": "Display label for the field.",
            "nullable": true
          },
          "dataType": {
            "$ref": "#/components/schemas/CustomFieldDataType"
          },
          "currentValue": {
            "type": "string",
            "description": "The current value on the client record.",
            "nullable": true
          },
          "instructions": {
            "type": "string",
            "description": "Optional instructions for this field (with tokens resolved).",
            "nullable": true
          },
          "isRequired": {
            "type": "boolean",
            "description": "Whether this field must be filled before completing the step."
          },
          "sortOrder": {
            "type": "integer",
            "description": "Display order within the step.",
            "format": "int32"
          },
          "displayWidth": {
            "$ref": "#/components/schemas/FieldDisplayWidth"
          },
          "options": {
            "type": "string",
            "description": "JSON array of allowed values for Select/MultiSelect data types.",
            "nullable": true
          },
          "maxLength": {
            "type": "integer",
            "description": "Maximum character length for Text and TextArea types.",
            "format": "int32",
            "nullable": true
          },
          "validationPattern": {
            "type": "string",
            "description": "Client-facing validation regex pattern.",
            "nullable": true
          },
          "validationMessage": {
            "type": "string",
            "description": "Client-facing validation error message.",
            "nullable": true
          },
          "booleanDisplayMode": {
            "$ref": "#/components/schemas/BooleanDisplayMode"
          },
          "defaultValue": {
            "type": "string",
            "description": "Optional default value configured on the step template.\nUsed to pre-fill the input when the user opens the form.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A single field with its current value and rendering metadata."
      },
      "WorkflowStepClientDataValueDto": {
        "type": "object",
        "properties": {
          "clientField": {
            "$ref": "#/components/schemas/ClientCsvTargetField"
          },
          "customFieldDefinitionCode": {
            "type": "string",
            "description": "The custom field definition code (mutually exclusive with ClientField).",
            "nullable": true
          },
          "value": {
            "type": "string",
            "description": "The value to set.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "A single field value being saved."
      },
      "WorkflowStepDetailsDto": {
        "type": "object",
        "properties": {
          "step": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "description": {
            "type": "string",
            "description": "The description of the workflow step",
            "nullable": true
          },
          "workflowGroup": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "groupDeadline": {
            "type": "string",
            "description": "The deadline for the workflow group containing this step",
            "format": "date-time",
            "nullable": true
          },
          "status": {
            "$ref": "#/components/schemas/TaskItemStatus"
          },
          "isOverdue": {
            "type": "boolean",
            "description": "Indicates if the workflow step is overdue (GroupDeadline is before today and status is not Completed or Skipped)",
            "readOnly": true
          },
          "blockedReason": {
            "type": "string",
            "description": "The reason this step is blocked. Only populated when Status is Blocked.",
            "nullable": true
          },
          "completedDate": {
            "type": "string",
            "description": "When this workflow step was completed (if applicable)",
            "format": "date-time",
            "nullable": true
          },
          "assignedTo": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "assignedTeam": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "canStart": {
            "type": "boolean",
            "description": "Indicates whether this step can be started based on its dependency requirements"
          },
          "checklist": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChecklistItemDto"
            },
            "description": "Checklist items for this workflow step",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Details about a specific workflow step when a TaskItemDto represents a workflow step view"
      },
      "WorkflowStepDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "timeEstimateMinutes": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "stepNumber": {
            "maximum": 2147483647,
            "minimum": 0,
            "type": "integer",
            "description": "The step number within the workflow group.\nUsed for ordering steps and referencing dependencies.\nIf 0-based numbering is provided, it will be automatically converted to 1-based.",
            "format": "int32"
          },
          "stepType": {
            "$ref": "#/components/schemas/WorkflowStepType"
          },
          "autoExecute": {
            "type": "boolean",
            "description": "Whether this step executes automatically when its dependencies are met.\nFalse means the user must manually trigger execution.\nOnly relevant for executable step types (SendEmail, DocumentRequest, ClientConfirmation)."
          },
          "dependsOnPreviousGroup": {
            "type": "boolean",
            "description": "Whether this step waits for all steps in the previous group to be completed before it can start."
          },
          "assignmentType": {
            "$ref": "#/components/schemas/WorkflowStepAssignmentType"
          },
          "assignedUser": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "assignedTeam": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "billableService": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "dependsOnStepNumbers": {
            "type": "array",
            "items": {
              "type": "integer",
              "format": "int32"
            },
            "description": "The step numbers that this step depends on (must be completed first).\nCan use either 0-based [0, 1] or 1-based [1, 2] numbering - 0-based will be auto-converted.\nExample: [1, 2] means this step depends on steps 1 and 2 being completed first.",
            "nullable": true
          },
          "emailStepConfiguration": {
            "$ref": "#/components/schemas/EmailStepConfigDto"
          },
          "documentRequestStepConfiguration": {
            "$ref": "#/components/schemas/DocumentRequestStepConfigDto"
          },
          "documentApprovalStepConfiguration": {
            "$ref": "#/components/schemas/DocumentApprovalStepConfigDto"
          },
          "clientConfirmationStepConfiguration": {
            "$ref": "#/components/schemas/ClientConfirmationStepConfigDto"
          },
          "sendDataFormStepConfiguration": {
            "$ref": "#/components/schemas/SendDataFormStepConfigDto"
          },
          "setServiceStageStepConfiguration": {
            "$ref": "#/components/schemas/SetServiceStageStepConfigDto"
          },
          "setPipelineStageStepConfiguration": {
            "$ref": "#/components/schemas/SetPipelineStageStepConfigDto"
          },
          "updateClientDataStepConfiguration": {
            "$ref": "#/components/schemas/UpdateClientDataStepConfigDto"
          },
          "checklist": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChecklistItemDto"
            },
            "description": "Checklist items for this workflow step template",
            "nullable": true
          },
          "condition": {
            "$ref": "#/components/schemas/ConditionDto"
          },
          "clientTypes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClientType"
            },
            "description": "The types of clients this step is applicable to.\nAn empty list means the step applies to all client types.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "DTO for workflow steps within a workflow group.\nUsed for both create/update requests and GET responses for workflow templates."
      },
      "WorkflowStepEmailPreviewDto": {
        "type": "object",
        "properties": {
          "subject": {
            "type": "string",
            "description": "Rendered subject line with Liquid tokens resolved.",
            "nullable": true
          },
          "bodyHtml": {
            "type": "string",
            "description": "Rendered body HTML with header/footer/theme applied and Liquid tokens resolved.",
            "nullable": true
          },
          "toRecipients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmailPreviewRecipientDto"
            },
            "description": "Resolved To recipients with names and email addresses.",
            "nullable": true
          },
          "ccRecipients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmailPreviewRecipientDto"
            },
            "description": "Resolved CC recipients with names and email addresses.",
            "nullable": true
          },
          "bccRecipients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmailPreviewRecipientDto"
            },
            "description": "Resolved BCC recipients with names and email addresses.",
            "nullable": true
          },
          "fromConfigCode": {
            "type": "string",
            "description": "Suggested From connection (email config code): the client manager match if one applies, else the tenant default.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Preview of a workflow step email with rendered content and resolved recipients.\nReturned before sending so the user can review what will be sent."
      },
      "WorkflowStepProgressDto": {
        "type": "object",
        "properties": {
          "stepNumber": {
            "type": "integer",
            "description": "Sequential step number within the task (1, 2, 3, etc.).\nUsed for referencing the step in API calls and ordering.\nUnique across all groups within this task.",
            "format": "int32"
          },
          "stepName": {
            "type": "string",
            "description": "The name of the workflow step from the template.\nDescribes what needs to be done in this step.",
            "nullable": true
          },
          "stepDescription": {
            "type": "string",
            "description": "The detailed description of the workflow step from the template.\nProvides instructions or context for completing the step.",
            "nullable": true
          },
          "stepTimeEstimateMinutes": {
            "type": "integer",
            "description": "The estimated time to complete the workflow step, in whole minutes.\nInherited from the WorkflowStep template for time planning and estimation.",
            "format": "int32",
            "nullable": true
          },
          "status": {
            "type": "string",
            "description": "The current status of this workflow step instance.\nUses TaskItemStatus enum values (NotStarted, InProgress, Blocked, Completed, Skipped).",
            "nullable": true
          },
          "blockedReason": {
            "type": "string",
            "description": "The reason this step is blocked. Only returned when the status is \"Blocked\".",
            "nullable": true
          },
          "assignedUser": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "assignedTeam": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "completedByUser": {
            "$ref": "#/components/schemas/CodeAndNameDto"
          },
          "completedDate": {
            "type": "string",
            "description": "The date and time when this step was completed.\nNull if the step is not yet completed.\nUsed for tracking completion timeline and performance metrics.",
            "format": "date-time",
            "nullable": true
          },
          "canStart": {
            "type": "boolean",
            "description": "Whether this step can be started based on its dependencies.\nTrue if all prerequisite steps are completed, false otherwise.\nUsed by the UI to enable/disable step actions."
          },
          "stepType": {
            "$ref": "#/components/schemas/WorkflowStepType"
          },
          "autoExecute": {
            "type": "boolean",
            "description": "Whether this step executes automatically when its dependencies are met.\nFalse means the user must manually trigger execution.\nOnly relevant for executable step types (SendEmail, DocumentRequest, ClientConfirmation)."
          },
          "dependsOnPreviousGroup": {
            "type": "boolean",
            "description": "Whether this step waits for all steps in the previous group to be completed before it can start."
          },
          "emailStepConfiguration": {
            "$ref": "#/components/schemas/EmailStepConfigDto"
          },
          "emailExecutionState": {
            "$ref": "#/components/schemas/EmailExecutionStateDto"
          },
          "documentRequestStepConfiguration": {
            "$ref": "#/components/schemas/DocumentRequestStepConfigDto"
          },
          "documentRequestExecutionState": {
            "$ref": "#/components/schemas/DocumentRequestExecutionStateDto"
          },
          "documentApprovalStepConfiguration": {
            "$ref": "#/components/schemas/DocumentApprovalStepConfigDto"
          },
          "documentApprovalExecutionState": {
            "$ref": "#/components/schemas/DocumentApprovalExecutionStateDto"
          },
          "linkedDocumentApprovalStatus": {
            "$ref": "#/components/schemas/ClientApprovalStatus"
          },
          "clientConfirmationStepConfiguration": {
            "$ref": "#/components/schemas/ClientConfirmationStepConfigDto"
          },
          "clientConfirmationExecutionState": {
            "$ref": "#/components/schemas/ClientConfirmationExecutionStateDto"
          },
          "sendDataFormStepConfiguration": {
            "$ref": "#/components/schemas/SendDataFormStepConfigDto"
          },
          "sendDataFormExecutionState": {
            "$ref": "#/components/schemas/SendDataFormExecutionStateDto"
          },
          "setServiceStageStepConfiguration": {
            "$ref": "#/components/schemas/SetServiceStageStepConfigDto"
          },
          "setPipelineStageStepConfiguration": {
            "$ref": "#/components/schemas/SetPipelineStageStepConfigDto"
          },
          "updateClientDataStepConfiguration": {
            "$ref": "#/components/schemas/UpdateClientDataStepConfigDto"
          },
          "notes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NoteDto"
            },
            "description": "Notes attached to this workflow step.\nUses the TaskItemNote system for rich note support including pinning.",
            "nullable": true
          },
          "dependsOnSteps": {
            "type": "array",
            "items": {
              "type": "integer",
              "format": "int32"
            },
            "description": "Sequential step numbers that this step depends on within this task.\nThese are the StepNumber values (e.g., [2, 5, 7]).\nThese steps must be completed before this step can be started.",
            "nullable": true
          },
          "checklist": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChecklistItemDto"
            },
            "description": "Checklist items for this workflow step instance",
            "nullable": true
          },
          "lastChasedDate": {
            "type": "string",
            "description": "When this step was last chased. Null if never chased.",
            "format": "date-time",
            "nullable": true
          },
          "nextChaseDate": {
            "type": "string",
            "description": "When this step is next due for chasing. Null if chasing is disabled.",
            "format": "date-time",
            "nullable": true
          },
          "isOmitted": {
            "type": "boolean",
            "description": "Whether this step is omitted because its visibility condition is not met by the\ntask's primary client. Omitted steps are excluded from progress counts, satisfy\ndependencies, and cannot be actioned."
          },
          "omittedReason": {
            "type": "string",
            "description": "Human-readable explanation of why this step is omitted. Null when not omitted.",
            "nullable": true
          }
        },
        "additionalProperties": false,
        "description": "Represents the progress of a single workflow step within a TaskItem.\nContains both the step template information and the current execution status.\n            \nAPI Usage:\n- Part of TaskWorkflowProgressDto responses\n- Returned by individual step operations\n- Used for step-level progress tracking and assignment management"
      },
      "WorkflowStepReference": {
        "required": [
          "taskCode"
        ],
        "type": "object",
        "properties": {
          "taskCode": {
            "minLength": 1,
            "type": "string",
            "description": "The task code containing the workflow step."
          },
          "groupNumber": {
            "type": "integer",
            "description": "The group number within the workflow.",
            "format": "int32"
          },
          "stepNumber": {
            "type": "integer",
            "description": "The step number within the group.",
            "format": "int32"
          }
        },
        "additionalProperties": false,
        "description": "Identifies a specific workflow step within a task."
      },
      "WorkflowStepType": {
        "enum": [
          "Standard",
          "SendEmail",
          "DocumentRequest",
          "DocumentApproval",
          "ClientConfirmation",
          "SendDataForm",
          "SetServiceStage",
          "UpdateClientData",
          "SetPipelineStage"
        ],
        "type": "string"
      },
      "WorkingDaySettingsDto": {
        "type": "object",
        "properties": {
          "defaultHolidayAdjustment": {
            "$ref": "#/components/schemas/HolidayAdjustment"
          },
          "bankHolidayRegion": {
            "$ref": "#/components/schemas/BankHolidayRegion"
          },
          "workingDays": {
            "$ref": "#/components/schemas/WorkingDays"
          }
        },
        "additionalProperties": false,
        "description": "Working day settings for a tenant"
      },
      "WorkingDays": {
        "enum": [
          "None",
          "Monday",
          "Tuesday",
          "Wednesday",
          "Thursday",
          "Friday",
          "StandardWeek",
          "Saturday",
          "SixDayWeek",
          "Sunday",
          "AllDays"
        ],
        "type": "string"
      }
    },
    "securitySchemes": {
      "ApiKey": {
        "type": "apiKey",
        "description": "API Key required in 'x-api-key' header",
        "name": "x-api-key",
        "in": "header"
      },
      "OAuth2": {
        "type": "oauth2",
        "description": "OAuth2 implicit flow",
        "flows": {
          "implicit": {
            "authorizationUrl": "https://id.sodiumhq.com/authorize",
            "scopes": {
              "openid": "OpenID Connect",
              "profile": "User profile",
              "email": "Email address"
            }
          }
        }
      }
    }
  },
  "security": [
    {
      "ApiKey": []
    },
    {
      "OAuth2": [
        "openid",
        "profile",
        "email"
      ]
    }
  ],
  "tags": [
    {
      "name": "Accounting",
      "description": "Integration with third-party accounting platforms. Provides endpoints to list customers from connected accounting systems, retrieve individual customer details, create new customers, and fetch invoices by customer. The accounting platform is determined by the Tenant.AccountingConnectionCode which references a ThirdPartyConnection."
    },
    {
      "name": "AI",
      "description": "AI-powered features for content generation and usage tracking. Includes endpoints to configure AI settings per tenant (API keys, model selection), generate content for various activities (service descriptions, proposals, tooltips), and retrieve token usage summaries for monitoring AI consumption. All content generation uses OpenRouter with configurable models."
    },
    {
      "name": "AML",
      "description": "Integration with third-party Anti-Money Laundering platforms. Provides endpoints to list, get, search, and create clients in connected AML systems, as well as retrieve and start risk assessments for individual AML clients. The AML platform is determined by the Tenant.AmlConnectionCode which references a ThirdPartyConnection."
    },
    {
      "name": "API Keys",
      "description": "API key management for programmatic access to the Sodium API. Provides endpoints to create new API keys with custom names and expiration dates, list all API keys for the authenticated user, retrieve individual API key details, update API key properties, and revoke API keys. API keys enable secure server-to-server integrations and automation workflows."
    },
    {
      "name": "Client Billable Services",
      "description": "Top-level client billable service queries not scoped to a single client. Returns lightweight summary projections designed for kanban board display, with filtering by service code and stage code. Also provides a PATCH endpoint for updating only the stage (used for drag-and-drop)."
    },
    {
      "name": "Client Billing - Line Items",
      "description": "Tenant-wide view of billing line items across all clients. Supports pagination and filtering by status, client, and billing date range. For client-scoped operations (approve, cancel) see the Client - Billing - Lines tag."
    },
    {
      "name": "Client Billing - Settings",
      "description": "Tenant-level settings for recurring client billing and invoicing defaults. Enable or disable the billing module, configure default invoice day of month, payment terms, line item approval requirements, and default accounting codes."
    },
    {
      "name": "Client Billing - Submissions",
      "description": "Tenant-wide view of invoice submissions across all clients. Supports pagination and filtering by status, client, and billing date range. For client-scoped operations (submit, retry, projected) see the Client - Billing - Submissions tag."
    },
    {
      "name": "Client Confirmations",
      "description": "Tenant-wide list of client confirmation workflow steps. Returns a paged list of confirmation steps across all clients with filtering by status and client code. Used by the Requests page to show outstanding client confirmations."
    },
    {
      "name": "Pending Workflow Steps",
      "description": "Manual-mode outbound workflow steps that are ready to send. Dependencies are met and a user needs to review and trigger the send. Used by the Requests page Ready to Send tab."
    },
    {
      "name": "External Proposals",
      "description": "Read-only access to proposals from external proposal platforms (e.g., Socket). The platform is determined by Tenant.ProposalConnectionCode which references a ThirdPartyConnection with the Proposals capability."
    },
    {
      "name": "Client Documents",
      "description": "Tenant-wide list of client documents. Returns a paged list of documents across all clients, defaulting to only those sent for client approval. Used by the Requests page to show outstanding document approvals."
    },
    {
      "name": "Client Pipelines",
      "description": "Top-level client pipeline card queries not scoped to a single client. Returns lightweight summary projections designed for kanban board display, with filtering by pipeline code and stage code."
    },
    {
      "name": "Client Portal - Access",
      "description": "Manage portal access for client contacts. Toggle portal access on or off for specific contacts on individual clients. When granting access, a PortalUser record is automatically created if one doesn't exist for the contact. Contacts must have an email address to be granted portal access."
    },
    {
      "name": "Client Portal - Settings",
      "description": "Tenant-level settings for the client portal. Configure the portal title and optional design theme. When no settings exist, the portal title defaults to the practice/tenant name."
    },
    {
      "name": "Client Portal - Users",
      "description": "Manage portal user accounts across the tenant. List all portal users and enable or disable individual portal user accounts. Disabling a portal user prevents them from logging in to the portal without revoking their per-client access grants."
    },
    {
      "name": "Client - Agent Authorisations",
      "description": "Manage HMRC 64-8 agent authorisation statuses for individual clients. Returns all 11 authorisation types with a user-managed status (Not Requested, Requested, Granted) and a computed IsRequired flag derived from the client's active or proposed services."
    },
    {
      "name": "Client - Billing - Lines",
      "description": "Billable line items generated from recurring client services. Line items are created by the billing engine and accumulate until bundled into an invoice submission. Supports listing, retrieval, and deletion. Items progress through statuses: Pending → Approved → Invoiced (or Cancelled)."
    },
    {
      "name": "Client - Billing - Submissions",
      "description": "Invoice submissions represent batches of approved billable line items pushed to the connected accounting platform. Each submission tracks the external invoice ID/number, submission status, and any error messages from failed attempts."
    },
    {
      "name": "Client - Business Details",
      "description": "Manage business-specific information for clients that are businesses (non-companies). Provides get and update operations for business details including trading name, business type, registration information, and other business-specific data. This is a one-to-one relationship with Client entities of type Business, complementing Company Details for corporate clients."
    },
    {
      "name": "Client - Contacts",
      "description": "Manage contacts associated with specific clients. Provides standard CRUD operations for client contacts including creation, retrieval, updating, and deletion. Client contacts are scoped to individual clients and include contact type, name, email, phone, and other contact information."
    },
    {
      "name": "Client - Custom Fields",
      "description": "Manage custom field values for individual clients. Custom fields are defined at the tenant level and values are stored per client. Supports getting all field definitions with their current values for a client, and setting/updating values with type validation (text, number, date, boolean, select, multi-select)."
    },
    {
      "name": "Client - Dates",
      "description": "Manage key dates for individual clients including year-end, tax deadlines, and other compliance-related dates. Provides get and save operations for client date management."
    },
    {
      "name": "Client - Document Requests",
      "description": "Manage document requests for clients. Create requests asking clients to provide specific documents, track submissions and review responses. Supports the full lifecycle: Draft → Open → Submitted → Accepted/Rejected/Cancelled. Documents can be uploaded by staff or portal clients, and submissions include comments and review workflows."
    },
    {
      "name": "Client - Documents",
      "description": "Manage documents associated with specific clients. Supports creating, listing, updating, and deleting client documents. Includes filtering by document type and review status. Documents uploaded by clients via the portal start with ReviewStatus=PendingReview and must be approved or rejected by an internal user. The list endpoint defaults to showing only Approved documents — use the reviewStatus filter parameter to view PendingReview or Rejected documents."
    },
    {
      "name": "Client - Email Rules",
      "description": "Rules that associate emails with a client. Each rule is an email address (e.g. john@acme.com), a domain (e.g. acme.com), or a specific message ID (GUID). Email addresses match that exact sender/recipient, domains match all emails from that domain, and message IDs pin a specific email to the client. The same value can be a rule for multiple clients."
    },
    {
      "name": "Client - Emails",
      "description": "Returns emails associated with a client based on its configured rules. Queries all connected mailboxes using the client's rules as filters and returns matching conversations. Supports direction, search, and pagination."
    },
    {
      "name": "Client - Links",
      "description": "Manage external links associated with specific clients. Provides CRUD operations for client links which can point to external resources, websites, or portals relevant to the client. Links include URL, description, and link type information."
    },
    {
      "name": "Client - Notes",
      "description": "Manage notes associated with specific clients. Supports creating, listing, updating, and deleting client notes with filtering capabilities. Notes can be used for tracking communications, observations, or important client information with timestamp and author tracking."
    },
    {
      "name": "Client - Pipelines",
      "description": "Manage a client's placements on sales pipelines (kanban cards). Provides CRUD operations for putting a client (typically an Active Prospect) on a pipeline, plus a PATCH endpoint for updating only the stage (used for drag-and-drop)."
    },
    {
      "name": "Client - Request & Chasing",
      "description": "Settings for client request email templates and automated chasing frequencies. Controls which content blocks are used for document request, approval, confirmation, and form submission emails, plus how often outstanding items are chased."
    },
    {
      "name": "Client - Services",
      "description": "Manage billable services associated with specific clients. Provides CRUD operations for linking BillableServices to individual clients, tracking which services are actively provided to each client. This represents the client-specific instances of services from the tenant's service catalog."
    },
    {
      "name": "Client - Settings",
      "description": "Tenant-level configuration for client field visibility and behavior. Provides get and update operations for controlling which client fields are enabled and displayed in lists (client manager, partner, associate, internal reference, external links). Includes settings for internal reference uniqueness validation. Requires PracticeDetails permissions to view or modify."
    },
    {
      "name": "Clients",
      "description": "Comprehensive client management including CRUD operations and task summaries. Supports filtering by manager, partner, status, type, and search terms."
    },
    {
      "name": "Clients - CSV Export",
      "description": "CSV-based client export with flexible column mapping. Start an export with optional column mappings (reuse saved import mappings or define ad-hoc mappings). If no mapping is provided, all fields are exported with enum names as headers. Filter clients by manager, partner, status, type, service code, or search term. Export jobs are processed asynchronously with a sync-when-fast pattern (waits up to 10 seconds). Poll for status and download the generated CSV via a time-limited URL."
    },
    {
      "name": "Clients - CSV Import",
      "description": "CSV-based client import with flexible column mapping. Upload a CSV file to get a preview with auto-suggested column mappings. Configure mappings using system defaults (Limited Company, Individual) or create custom mappings. Start the import with sync-when-fast pattern (waits up to 10 seconds, returns 201 if completed, 202 if still processing). Supports create-only, update-only, or create-and-update modes with configurable match fields (CompanyNumber, Code, Name, etc.)."
    },
    {
      "name": "Clients - Platform Import",
      "description": "Import clients from third-party platforms (e.g., Xero, QuickBooks) or via direct import with comprehensive data. Includes direct import (create client with all related data in one request), listing available clients from connected platforms, and importing selected or all clients with optional Companies House enrichment. Uses a sync-when-fast pattern for platform imports (waits up to 10 seconds, returns 201 if completed, 202 if still processing)."
    },
    {
      "name": "Clients - Saved Filters",
      "description": "Saved client filter management for personalized client views. Provides CRUD operations for creating, retrieving, updating, and deleting saved client filters. Users can save their preferred client filtering criteria (by manager, partner, associate, status, type, service, etc.) for quick access and reuse. Saved filters are scoped to individual users within a tenant."
    },
    {
      "name": "Clients - Services - Import",
      "description": "CSV-based client service import for bulk-assigning billable services to clients. Upload a native-format CSV to preview what will be created, updated, or left unchanged, then confirm to process. Supports creating new assignments and updating existing ones when values differ. Engager conversion endpoints analyze and convert Engager-format CSVs to native format (fully stateless)."
    },
    {
      "name": "Companies House",
      "description": "Integration with UK Companies House API for retrieving official company information. Provides endpoints to search companies by name or number, get detailed company information, retrieve company officers, fetch key dates for compliance tracking, view filing history with filtering by category, get specific filing details, and download official documents as PDFs."
    },
    {
      "name": "Contacts",
      "description": "Organization-wide contact management across all clients. Provides CRUD operations for contacts that can be associated with multiple clients. Includes an endpoint to retrieve all clients associated with a specific contact, enabling tracking of contact relationships across the tenant's client base."
    },
    {
      "name": "Content Blocks",
      "description": "Reusable content blocks for documents and proposals. Supports CRUD operations with filtering by category and search terms. Content blocks contain HTML content with image support (images are processed for URL transformation). Includes library access for creating content blocks from predefined templates. Used in proposal generation and document templating."
    },
    {
      "name": "CSV Mappings",
      "description": "Manage reusable CSV column mappings for client import and export operations. Mappings define how CSV columns map to client fields and can be saved for reuse across multiple imports or exports. System presets (Limited Company, Individual) are read-only. Tenant-specific mappings can be created, updated, and deleted."
    },
    {
      "name": "Custom Field Groups",
      "description": "Named groups for organising custom field definitions. Groups can optionally be displayed as their own card on entity detail pages. Supports CRUD operations with filtering by entity type."
    },
    {
      "name": "Custom Fields",
      "description": "Tenant-level custom field definitions for extending entity data. Define custom fields with types (Text, Number, Date, Boolean, Select, MultiSelect) that can be attached to entities like Clients. Supports CRUD operations with filtering by entity type and archived status."
    },
    {
      "name": "Custom Tokens",
      "description": "User-defined reusable tokens for document templates. Custom tokens use {{ Custom.TokenName }} syntax and prompt users to fill in values when generating documents. Each token has a name (the template identifier), optional description (prompt text), and optional default value."
    },
    {
      "name": "Data Form - Categories",
      "description": "Tenant-configurable categories for organizing forms. Provides CRUD operations for creating, retrieving, updating, and deleting form categories."
    },
    {
      "name": "Data Form - Requests",
      "description": "Form requests sent to clients. View submissions and review individual answers (accept or reject per field). Accepted answers apply the submitted value to the client record. Supports auto-accept for forms configured to skip manual review."
    },
    {
      "name": "Data Forms",
      "description": "Custom form management. Create forms with sections and questions, publish them, and send to clients individually or in bulk. Questions can map to client fields, custom fields, or be form-specific."
    },
    {
      "name": "Design Theme - Background Images",
      "description": "Manage background images on design themes for PDF rendering. Each background image can target specific pages (all, first only, all except first) and has configurable positioning (full page, corners, center, or custom coordinates), dimensions, and opacity."
    },
    {
      "name": "Design Themes",
      "description": "Design themes and branding customization for documents and proposals. Provides CRUD operations for themes, plus specialized endpoints to get the default theme, retrieve generated CSS for a specific theme (with optional CSS selector), and get CSS for the default theme. Themes control colors, fonts, and styling for client-facing documents."
    },
    {
      "name": "DirectDebit",
      "description": "Integration with third-party direct debit platforms. Provides endpoints to list payers (customers), create payers, list mandates, and create mandates. The direct debit platform is determined by Tenant.DirectDebitConnectionCode which references a ThirdPartyConnection with DirectDebit capability. A payer can have multiple mandates (e.g., different bank accounts). Create mandate returns authorization URL for customer approval."
    },
    {
      "name": "Document Requests",
      "description": "Tenant-wide list of document requests. Returns a paged list of document requests across all clients with filtering by status and client code. Used by the Requests page to show outstanding document requests."
    },
    {
      "name": "Document Templates",
      "description": "Document templates using Liquid syntax for dynamic content generation. Supports CRUD operations with filtering by template type. Includes library access for using predefined templates, and a render endpoint to generate PDFs from templates with provided data (client, partner, manager, practice, proposal details). Templates support design theme integration for consistent branding."
    },
    {
      "name": "Documents - Categories",
      "description": "Tenant-configurable document categories for organizing client documents. Provides CRUD operations for creating, retrieving, updating, and deleting custom document categories. Each tenant can define their own document categories with custom names and sort orders."
    },
    {
      "name": "Email - Broadcasts",
      "description": "Ad-hoc mass emails to a filtered set of clients with per-client Liquid token rendering. Provides draft CRUD, a pre-send resolved recipient list with skip warnings (missing contacts, email contact preference), per-client preview, test send to the current user, async sending with progress counters, a per-client delivery log, and cancellation. Recipient selection combines client filters with hand-picked additions and exclusions; recipients are resolved from client contact types, user types (manager/partner/associate/service manager), and static addresses — the same configuration shape as SendEmail workflow steps."
    },
    {
      "name": "Email - Configs",
      "description": "Email configuration management for tenant-specific SMTP or OAuth email providers. Provides CRUD operations for creating, retrieving, updating, and deleting email configurations. Supports multiple configurations per tenant with default/shared management, SMTP settings, and OAuth (Microsoft365/Google) flows. Includes a test endpoint to verify configurations."
    },
    {
      "name": "Email - History",
      "description": "Email history and delivery status tracking. Provides endpoints to view sent emails, check delivery status, and filter by various criteria including custom metadata. Enables tenants to check email delivery status."
    },
    {
      "name": "Email - Mailbox",
      "description": "Read, send, reply to, and manage emails in a tenant's connected mailbox. Only available for OAuth email configurations (Microsoft365/Google) that have ReadEnabled set to true. Conversations provide a thread-grouped view, while Messages provide a flat list. Supports filtering by direction (inbound/outbound) and search by subject or sender. Sending and replying requires SendEnabled to be true on the configuration. Includes OAuth reconnection for expired or misconfigured connections."
    },
    {
      "name": "Email - Settings",
      "description": "Email configuration and settings for tenant email communications. Provides get and update operations for email settings including sender details, email branding (header/footer content blocks, design theme), and other email-related preferences. Requires PracticeDetails permissions to view or modify."
    },
    {
      "name": "Engagement - Acceptance",
      "description": "Anonymous client-facing endpoints for engagement acceptance workflow. Enables clients to view engagement details without authentication, retrieve CSS for the acceptance page using the configured design theme, download proposal and engagement letter PDFs, and submit acceptance with digital signature and IP address tracking. All endpoints use a GUID-based secure link for access."
    },
    {
      "name": "Engagement - Settings",
      "description": "Settings and configuration specific to engagement generation and management. Accessed via the Practice endpoints at /tenants/{tenant}/practice/engagement-settings. Controls default proposal templates, design themes, email templates, and other engagement-specific preferences."
    },
    {
      "name": "Engagements",
      "description": "Comprehensive engagement creation, management, and client communication. Provides CRUD operations with filtering by status, client, and search terms. Includes specialized endpoints for uploading and downloading proposal PDFs and letters of engagement (base64-encoded content), sending engagement emails using configured templates with tracking, and retrieving email history for engagements. Engagements capture a snapshot of ClientBillableServices at a point in time."
    },
    {
      "name": "Holidays",
      "description": "Tenant-specific custom holidays (e.g., company anniversary, office closure dates). Provides CRUD operations for managing holidays that are specific to your organization. These holidays are combined with bank holidays (based on Working Days region setting) when calculating task scheduling and holiday adjustments."
    },
    {
      "name": "Import Jobs",
      "description": "Asynchronous import job status tracking and management. Provides endpoints to retrieve the current status of import jobs initiated from third-party platforms (e.g., client imports), list all import jobs for a tenant with progress details, and poll for job completion. Import jobs track total items, processed items, success count, failure count, and overall status (queued, in progress, completed, failed, cancelled)."
    },
    {
      "name": "Marketing",
      "description": "Anonymous public marketing endpoints. Brevo-proxied mailing list subscription used by the marketing website."
    },
    {
      "name": "Media Library",
      "description": "Image and media asset management with Azure Blob Storage integration. Supports creating image assets via file upload, retrieving assets with download URLs (SAS URLs), updating asset metadata, deleting assets, listing assets with download URLs, and streaming image content with caching support (ETag-based 304 Not Modified responses). All images are stored in Azure Blob Storage with SHA-256 hash tracking."
    },
    {
      "name": "Metadata",
      "description": "System metadata including enums, display names, colors, icons, and configuration options for all system enums. Provides read-only endpoints for retrieving metadata for enums such as client statuses, task statuses, service categories, billing frequencies, permissions, and many others. Also includes third-party platform metadata with capabilities and OAuth configuration details."
    },
    {
      "name": "Packages",
      "description": "Public endpoints for listing packages and their pricing tiers. Packages define which feature modules are available, and each package has its own set of pricing tiers."
    },
    {
      "name": "Pipeline - Intake Tasks",
      "description": "Templates for intake tasks that are created automatically when a client (typically an Active Prospect) is added to a pipeline. Each template defines the task name, due-date offset from the card's start date, assignment, optional workflow, category, and checklist. The pipeline sibling of Service - Onboarding Tasks."
    },
    {
      "name": "Pipelines",
      "description": "Tenant-level sales pipeline catalog management. Pipelines are prospect funnels with user-defined kanban stages and no pricing/proposal concerns. Provides CRUD operations with filtering by archived status, stages, kanban visibility, and search, plus library access for importing pre-built pipelines."
    },
    {
      "name": "Practice",
      "description": "Practice-level settings and configuration for the tenant. Includes endpoints to get and update practice details (firm name, address, contact information, professional body memberships, etc.). Requires PracticeDetails permissions to view or modify."
    },
    {
      "name": "Professional Clearance",
      "description": "Professional clearance letter management for client transitions. Provides CRUD operations for professional clearance request items (document and information requests sent to previous accountants), settings configuration for PCL emails, client-specific endpoints to retrieve applicable PCR items (filtered by billable services and including global items), and sending professional clearance letters via email with template variable substitution."
    },
    {
      "name": "Reports",
      "description": "Curated, typed, read-only reports over the tenant's operational data. Each report accepts a preset or custom date range plus entity filters (service, client, user, team, category) and returns headline KPIs with breakdown rows carrying entity codes for drill-down, plus a synchronous CSV export sibling. Report #1 is Service Delivery Turnaround: how fast tasks complete versus their due and statutory dates, grouped by service, client, assignee, or month, with a per-service workflow-step bottleneck drill-down splitting client-wait time from internal time. Requires Reports permissions; CSV export requires Export."
    },
    {
      "name": "Revenue Ranges",
      "description": "Tenant-configurable revenue ranges for client classification and pricing. Provides CRUD operations for creating, retrieving, updating, and deleting custom revenue ranges. Revenue ranges are used to categorize clients by annual revenue and enable revenue-based pricing overrides for billable services. Each tenant can define their own revenue ranges with custom names and sort orders."
    },
    {
      "name": "Sales Pipeline - Settings",
      "description": "Tenant-level settings for the Sales Pipeline feature. A tenant singleton exposing whether the feature is enabled — when off (the default) the pipeline UI is hidden and no pipeline automations run; when on, Active Prospects are also included in the tenant's billable client count."
    },
    {
      "name": "Service - Onboarding Tasks",
      "description": "Templates for one-off tasks that are automatically created when a client takes on a billable service. When a ClientBillableService becomes Active, the system creates TaskItems from matching OnboardingTaskTemplates. Each template belongs to a specific BillableService and defines task details like name, description, due date offset from service start, assignment rules, and optional workflow."
    },
    {
      "name": "Service - Packages",
      "description": "Service package management for bundling multiple billable services together. Provides CRUD operations for creating, retrieving, updating, and deleting service packages. Each package contains a list of billable services with pre-configured billing frequency, pricing options, and pre-answered pricing factors. Packages can be applied to clients in bulk, creating multiple ClientBillableService records at once with the pre-configured settings."
    },
    {
      "name": "Services",
      "description": "Tenant-level billable services catalog management. Provides CRUD operations with filtering by category, client type, archived status, and search terms. Includes library access for creating services from templates, AI-powered service generation from service names (generates description and pricing), pricing factor generation for existing services, and creating services from library templates with optional property overrides."
    },
    {
      "name": "Subscription",
      "description": "Tenant subscription management. View the current subscription, subscription history, change packages, and cancel subscriptions. Cancelling ends the current subscription immediately and marks the tenant as cancelled. Choosing a new plan via PUT clears the cancellation. The pricing tier is automatically determined from the tenant's active client count."
    },
    {
      "name": "Subscription - Billing",
      "description": "Billing account management for tenant subscriptions. Create and manage billing accounts, set up Direct Debit mandates via GoCardless, and view invoices. Only tenant administrators can access billing endpoints."
    },
    {
      "name": "Subscription - Discounts",
      "description": "Discount code management for tenant subscriptions. Redeem promotional discount codes to receive percentage-based billing discounts, view the active discount, or remove it to apply a different code. Discounts are applied automatically during monthly billing."
    },
    {
      "name": "Task - Emails",
      "description": "Returns email conversations that have been explicitly linked to a task."
    },
    {
      "name": "Task - Notes",
      "description": "Manage notes associated with specific tasks. Supports creating, listing, updating, and deleting task notes. Notes can be pinned for priority visibility (PinnedLevel > 0) and include author tracking and timestamps. Useful for collaboration and tracking important information related to tasks."
    },
    {
      "name": "Task - Workflow Notes",
      "description": "Manage notes associated with specific workflow steps within tasks. Supports creating, listing, updating, and deleting step-level notes. Notes can be pinned for priority visibility (PinnedLevel > 0) and include author tracking and timestamps. Useful for documenting work done on specific workflow steps."
    },
    {
      "name": "Task - Workflows",
      "description": "Task workflow progress tracking and step management for individual tasks. Provides endpoints to retrieve workflow groups with steps and progress statistics, initialize or reset workflow steps for a task (clears existing progress), remove workflow assignments from tasks, and update individual workflow steps (status, assignment, email configuration, time tracking). Supports customizing email recipients and execution mode for SendEmail steps before execution. All operations validate dependencies and maintain workflow integrity."
    },
    {
      "name": "Tasks",
      "description": "Comprehensive task management including creation, assignment, tracking, and filtering. Supports listing tasks with flexible date range handling, overdue filtering, agenda mode (including workflow steps), and filtering by client, user, recurring task, category, status, and saved filters. Can optionally include projected (virtual) tasks alongside materialized tasks. Provides full CRUD operations plus bulk update (status and/or assigned user) with multi-tenant scoping."
    },
    {
      "name": "Tasks - Categories",
      "description": "Tenant-configurable task categories for organizing and classifying tasks. Provides CRUD operations for creating, retrieving, updating, and deleting custom task categories. Each tenant can define their own task categories with custom names and sort orders to organize tasks according to their specific workflow and organizational needs."
    },
    {
      "name": "Tasks - Focus Config",
      "description": "Per-user configuration for the Task Focus Panel sidebar. Provides GET (auto-creates empty default) and PUT (upsert) operations for managing which saved task filters appear in the focus panel. Each item references a user's own saved task filter with optional label, sort order, and color. One config per user per tenant."
    },
    {
      "name": "Tasks - Projected",
      "description": "Projected (virtual) task items generated from recurring tasks that haven't been materialized yet. Provides endpoints to list projected tasks within date ranges with filtering, retrieve individual projected tasks by composite code (format: proj-{recurringTaskCode}-{clientCode}-{yyyyMMdd}), materialize projected tasks into real database records, and retrieve workflow groups for projected tasks with resolved assignments. Projected tasks are excluded from results once materialized."
    },
    {
      "name": "Tasks - Recurring",
      "description": "Recurring task templates and scheduling for automated task generation. Supports CRUD operations with filtering capabilities, plus endpoints to manage client associations (get/update specific clients for a recurring task) and service associations (get/update billable services that trigger task generation). Recurring tasks generate projected tasks based on configured recurrence patterns."
    },
    {
      "name": "Tasks - Saved Filters",
      "description": "Saved task filter management for personalized task views. Provides CRUD operations for creating, retrieving, updating, and deleting saved task filters. Users can save their preferred task filtering criteria (by client, status, date range, assigned user, etc.) for quick access and reuse. Saved filters are scoped to individual users within a tenant."
    },
    {
      "name": "Teams",
      "description": "Team management for group task assignment. Provides CRUD operations for creating, retrieving, updating, and deleting teams. Includes member management endpoints for adding and removing users from teams, and a 'my teams' endpoint for listing the current user's teams. Teams enable work to be assigned to a group rather than an individual, allowing team members to pick tasks from a shared queue."
    },
    {
      "name": "Tenants",
      "description": "Multi-tenant organization management and configuration. Provides endpoints to create new tenants with package assignment and invite code validation, list all tenants the authenticated user belongs to, retrieve tenant details by code, get the current user's role and permissions within a tenant, update tenant information, and delete tenants (with validation to prevent deletion if clients exist). Tenants represent separate organizations within the multi-tenant system."
    },
    {
      "name": "Third-Party Connections",
      "description": "OAuth connections and integrations to third-party platforms (accounting systems, practice management tools, etc.). Provides CRUD operations for managing connections, an anonymous OAuth callback endpoint for handling authorization code exchanges, and an endpoint to set organization IDs for connections in Initialising status to activate them. Supports platforms like QuickBooks, Xero, and others with OAuth2 authentication."
    },
    {
      "name": "Time Tracking",
      "description": "Time entries recorded by team members, optionally linked to a client and/or task. Supports CRUD operations with filtering by user, client, task, date range, billable flag, and billed state. Billable entries carry an hourly rate snapshot and can later be converted into client billing line items."
    },
    {
      "name": "Time Tracking - Settings",
      "description": "Tenant-level settings for time recording. Enable or disable time tracking (hides all time tracking UI when off), require entries to be linked to a client or task, and set the practice default hourly rate."
    },
    {
      "name": "Time Tracking - Timer",
      "description": "The calling user's live timer — at most one per user. Start or update it, read it (returns null when nothing is running), or discard it. Stopping is client-side: the elapsed time pre-fills a time entry and the timer is discarded once that entry is saved."
    },
    {
      "name": "User - Account",
      "description": "User account management endpoints including retrieving unused invite codes for the authenticated user. These endpoints help users manage their invite code allocations for creating new tenants."
    },
    {
      "name": "User - Invitations",
      "description": "User invitation workflow for adding users to tenants. Provides endpoints to list pending invitations for the authenticated user, accept or decline invitations (validates email verification), and send invitation emails to users. Invitations include token-based security, email verification requirements, and status tracking (pending, accepted, declined)."
    },
    {
      "name": "User View Preferences",
      "description": "Per-user view preferences for storing UI configuration as JSON. Each user can have one preference per view key (e.g. \"dashboard\" for dashboard layout). GET auto-creates an empty default; PUT creates or updates the configuration."
    },
    {
      "name": "Users",
      "description": "User management and authentication within the application. Provides endpoints to get the current authenticated user's profile, verify email addresses using verification keys from email links (with token expiration handling), and resend verification emails to authenticated users. Also includes tenant-scoped user management (CRUD operations) accessed via /tenants/{tenant}/users for managing users within specific tenants."
    },
    {
      "name": "Workflows",
      "description": "Reusable workflow definitions and templates for task automation. Provides CRUD operations for creating, retrieving, updating, and deleting workflow templates. Includes library access for browsing predefined templates, importing workflows from the library, and AI-powered workflow generation from a name and description. Workflows define sequences of steps, dependencies, assignments, and completion requirements that can be applied to tasks to standardize processes across the organization."
    },
    {
      "name": "Working Days",
      "description": "Configure working days, holidays, and task scheduling adjustments. Provides get and update operations for bank holiday region (England, Wales, Scotland, Northern Ireland) and default holiday adjustment behavior when tasks fall on non-working days. Also includes an endpoint to list bank holidays for the configured region."
    }
  ]
}
