{
  "openapi": "3.0.0",
  "info": {
    "title": "banta API",
    "description": "# Introduction\n\nThe banta API connects the mortgage management platform to your other systems: marketing sites and landing pages, CRMs, automation tools (Make, Zapier, n8n), BI and internal tools. Every call operates on the data of the organization that owns the API key - and only on it.\n\n## What you can do\n\n- **Leads** - capture leads from forms and campaigns, update their status, list and search them.\n- **Customers and contacts** - manage customer records and professional contacts (bankers, appraisers, lawyers).\n- **Mortgage files** - create and update files, including borrowers, incomes, obligations and purposes.\n- **File management** - tasks, notes, reminders, watchers, file contacts and milestones.\n- **Documents** - document statuses, signatures and generated documents (read).\n- **Billing** - charges, payments, calculator mixes and file analyses.\n- **System lists** - fixed values (employment types, mortgage types, statuses) for building forms.\n\n## Base URL\n\nAll endpoints live under:\n\n```\nhttps://app.banta.co.il/api-service\n```\n\nFor example, listing leads: `GET https://app.banta.co.il/api-service/leads`.\n\n## Data format\n\n- **JSON only** - requests with a body are sent with `Content-Type: application/json`, and responses are always UTF-8 JSON.\n- **IDs** - every identifier is a UUID.\n- **Dates** - ISO 8601. Date-time fields (`created_at`, `updated_at`) include a time zone; date-only fields are `YYYY-MM-DD`.\n- **Amounts** - numbers (not strings), in Israeli shekels (ILS) unless a field says otherwise.\n- **Text** - much of the data your organization stores (names, notes, statuses) is in Hebrew. Make sure your client handles UTF-8 end to end.\n- **Errors** - one consistent shape, see [Errors](#description/errors).\n\n## Versioning and compatibility\n\nThe current API version is 1.0.0. API URLs do not include a version number. Additive changes - new fields or new endpoints - can ship at any time, so write clients that ignore fields they don't recognize. Breaking changes are announced in advance on the [Changelog](#description/changelog).\n\n## Docs for AI agents\n\nAll of this documentation is also published as clean text for AI agents and LLMs: [`llms.txt`](https://docs.banta.co.il/llms.txt), [`llms-full.txt`](https://docs.banta.co.il/llms-full.txt) and a Markdown file per endpoint. You can also connect banta directly to Claude or ChatGPT over MCP. See [AI agents & MCP](#description/ai-agents).\n\n## Support\n\nAPI questions: [support@banta.co.il](mailto:support@banta.co.il). Product guides (in Hebrew) are in the [Help Center](https://help.banta.co.il). This documentation is also available [in Hebrew](https://docs.banta.co.il/he/).\n\n# Quickstart\n\n## 1. Create an API key\n\n1. Sign in to banta as a user who is allowed to manage the organization's integrations.\n2. Go to [Organization settings → Integrations → API](https://app.banta.co.il/organization/settings?group=integrations&tab=api).\n3. Create a new key, give it a name that describes its use (for example \"Website lead form\") and choose its permissions. Grant the minimum you need - see [Authentication & permissions](#description/authentication).\n4. **Copy the key right away.** It is shown only once and cannot be retrieved later.\n\n> Keep the key on the server side only (environment variables or a secrets vault). Never embed it in code that runs in a browser or a mobile app.\n\n## 2. Your first call\n\nFetch the five most recent leads:\n\n```bash\ncurl \"https://app.banta.co.il/api-service/leads?limit=5\" \\\n  -H \"x-api-key: $BANTA_API_KEY\"\n```\n\nList responses carry a total count:\n\n```json\n{\n  \"data\": [\n    {\n      \"id\": \"6f1c2a4e-0b7d-4b8e-9a51-2f6c3d8e9a10\",\n      \"first_name\": \"Israel\",\n      \"last_name\": \"Israeli\",\n      \"phone\": \"050-0000000\",\n      \"status\": \"new\",\n      \"created_at\": \"2026-10-01T09:30:00+00:00\"\n    }\n  ],\n  \"count\": 128\n}\n```\n\n`count` is the number of records that match the query - not just the ones on the current page. See [Pagination & search](#description/conventions).\n\n## 3. Create a lead\n\n```bash\ncurl -X POST \"https://app.banta.co.il/api-service/leads\" \\\n  -H \"x-api-key: $BANTA_API_KEY\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"first_name\": \"Israel\",\n    \"last_name\": \"Israeli\",\n    \"phone\": \"050-0000000\",\n    \"email\": \"israel@example.com\",\n    \"source\": \"website\"\n  }'\n```\n\nA successful call returns `201 Created` with the full lead, including its new `id`.\n\n## The same call in popular languages\n\n**JavaScript (Node.js 18+):**\n\n```js\nconst res = await fetch('https://app.banta.co.il/api-service/leads', {\n  method: 'POST',\n  headers: {\n    'x-api-key': process.env.BANTA_API_KEY,\n    'Content-Type': 'application/json',\n  },\n  body: JSON.stringify({\n    first_name: 'Israel',\n    last_name: 'Israeli',\n    phone: '050-0000000',\n    source: 'website',\n  }),\n})\n\nif (!res.ok) {\n  const err = await res.json()\n  throw new Error(`banta API ${res.status}: ${err.error} ${err.details ?? ''}`)\n}\nconst lead = await res.json()\n```\n\n**Python:**\n\n```python\nimport os\nimport requests\n\nres = requests.post(\n    \"https://app.banta.co.il/api-service/leads\",\n    headers={\"x-api-key\": os.environ[\"BANTA_API_KEY\"]},\n    json={\n        \"first_name\": \"Israel\",\n        \"last_name\": \"Israeli\",\n        \"phone\": \"050-0000000\",\n        \"source\": \"website\",\n    },\n    timeout=30,\n)\nres.raise_for_status()\nlead = res.json()\n```\n\n## Next steps\n\n- Every endpoint in this reference has a **Test Request** button. Requests go straight from your browser to banta, with no intermediary server. The key you enter is kept only in the open tab and is cleared when you close it. Note that these are real requests against your organization's data.\n- [Authentication & permissions](#description/authentication) - how to scope a key down.\n- [Errors](#description/errors) and [Rate limits](#description/rate-limits) - how to handle failures.\n\n# Authentication & permissions\n\n## API keys\n\nEvery request must carry an API key in the `x-api-key` header:\n\n```http\nGET /api-service/leads HTTP/1.1\nHost: app.banta.co.il\nx-api-key: YOUR_API_KEY\n```\n\n- Keys are created in [Organization settings → Integrations → API](https://app.banta.co.il/organization/settings?group=integrations&tab=api) and shown only once. banta stores only a hash of the key.\n- Each key belongs to exactly one organization. Every call sees and changes only that organization's data; there is no way to reach another organization's data.\n- You can revoke a key at any time from the same screen, effective immediately. Keys can also have an expiry date, after which they are rejected.\n- Every successful write (create, update, delete) is recorded in the organization's API audit log: the key, the endpoint, the affected record, the status and the duration. Request and response bodies are not stored.\n\n> A key is equivalent to a password with access to customers' personal data. Use it server-side only, never commit it to code or git, and rotate it immediately if you suspect it leaked.\n\n## Permissions\n\nEach key has a list of permissions. Every request is checked by **resource** and **action**:\n\n| HTTP method | Action |\n|---|---|\n| `GET` | `read` |\n| `POST`, `PUT`, `PATCH` | `write` |\n| `DELETE` | `delete` |\n\nThe resources are `leads`, `customers`, `contacts`, `mortgage-files`, `tasks` and `lists`. Every route nested under a mortgage file (`/mortgage-files/{id}/...` - borrowers, notes, charges, milestones and so on) is checked against the `mortgage-files` resource.\n\nPermission values:\n\n| Value | Meaning |\n|---|---|\n| `admin` or `*` | Full access to every resource and action |\n| `leads:*` | Every action on one resource |\n| `leads:read`, `leads:write`, `leads:delete` | One action on one resource |\n| `read` | Read every resource |\n| `write` | Create and update on every resource (**not** delete) |\n\nThe key creation screen offers four presets: **Read only** (`read`), **Read & write** (`read` + `write`, without deleting), **Full access** (`admin`) and **Custom**, where you pick resource/action pairs from a table.\n\nDeleting always requires an explicit permission: `admin`/`*`, `resource:*` or `resource:delete`.\n\nExample: a website lead form needs only `leads:write`. A BI dashboard needs only `read`.\n\n## Authentication responses\n\n| Status | When | What to do |\n|---|---|---|\n| `401 Unauthorized` | The key is missing, invalid or revoked | Check the header and the key. The `reason` field says why. |\n| `403 Forbidden` | The key is valid but lacks permission for this action on this resource | Add the permission or create a dedicated key |\n\n`reason` values on a 401:\n\n| `reason` | Meaning |\n|---|---|\n| `missing_api_key` | The `x-api-key` header was not sent or is empty |\n| `malformed_api_key` | The key contains whitespace or invalid characters (usually a copy-paste error) |\n| `invalid_api_key` | The key does not exist, was revoked or has expired |\n| `auth_service_error` | A temporary failure in the authentication service. Retry in a few seconds |\n\n```json\n{\n  \"reason\": \"invalid_api_key\",\n  \"error\": \"Unauthorized\",\n  \"status\": 401\n}\n```\n\n## CORS\n\nThe API returns permissive CORS headers so that the **Test Request** button in these docs works from the browser. That does **not** make it OK to call the API from client-side code in production: anyone opening the developer tools would see the key. Put a server layer (a backend, a serverless function or an automation tool) in front of the API to hold the key.\n\n# Pagination, search & responses\n\n## Response shape\n\n| Call | Status | Body |\n|---|---|---|\n| List (`GET /leads`) | `200` | An object `{ \"data\": [...], \"count\": N }` |\n| Single record (`GET /leads/{id}`) | `200` | The record itself |\n| Create (`POST`) | `201` | The created record, including its `id` |\n| Update (`PUT` / `PATCH`) | `200` | The updated record |\n| Delete (`DELETE`) | `200` | A confirmation, e.g. `{ \"success\": true, \"message\": \"...\" }` |\n\nOn paginated lists, `count` is the total number of records that match the query, not just the ones on the current page. On short, unpaginated lists (for example borrowers in a file), `count` equals the array length.\n\n## Pagination\n\nLarge lists are paginated with two parameters:\n\n| Parameter | Default | Maximum | Description |\n|---|---|---|---|\n| `limit` | `50` | `500` | Records per page |\n| `offset` | `0` | `1000000` | Records to skip |\n\nAn invalid value (negative or non-numeric) does not return an error - it falls back to the default. A value above the maximum is capped. Results are sorted newest first (`created_at` descending) unless an endpoint says otherwise.\n\nWalking through every record:\n\n```js\nasync function fetchAll(path) {\n  const limit = 500\n  const all = []\n  for (let offset = 0; ; offset += limit) {\n    const res = await fetch(`https://app.banta.co.il/api-service${path}?limit=${limit}&offset=${offset}`, {\n      headers: { 'x-api-key': process.env.BANTA_API_KEY },\n    })\n    if (!res.ok) throw new Error(`HTTP ${res.status}`)\n    const { data, count } = await res.json()\n    all.push(...data)\n    if (data.length < limit || all.length >= count) return all\n  }\n}\n```\n\n> When paging through a lot of data, mind the [rate limit](#description/rate-limits) of 60 requests per minute. Pages of 500 are the most efficient way through.\n\n## Search\n\nEndpoints that support search accept a `search` parameter. Search is case-insensitive and matches the term inside several fields at once (for example name, phone and email). The exact fields are listed on each endpoint.\n\n```bash\ncurl \"https://app.banta.co.il/api-service/customers?search=Israeli\" -H \"x-api-key: $BANTA_API_KEY\"\n```\n\nThe characters `, ( ) % _ \\ \" '` are stripped from the term before searching. Search for phone numbers the way they are stored, with or without dashes.\n\n## Filtering\n\nSome lists accept extra filter parameters, for example `status` on the leads list. Available parameters are listed on each endpoint.\n\n## PUT vs PATCH\n\nOn resources that support both, `PUT` and `PATCH` behave the same: a **partial update**. Send only the fields you want to change; fields you don't send are left as they are. Fields that cannot be updated (such as `id`, `organization_id` and `created_at`) are silently ignored. If no updatable field is sent, the API returns `400 No updatable fields provided`.\n\n## Fixed values\n\nEnum values (employment types, mortgage types, statuses and so on) are available from the endpoints under [System lists](#tag/lists). Use them to build forms instead of hard-coding values. Lead and file statuses can be customized per organization, so read them from `/leads/statuses` and `/mortgage-files/statuses`.\n\n# Errors\n\n## Error response shape\n\nEvery error is returned as JSON in the same shape:\n\n```json\n{\n  \"error\": \"Lead not found or access denied\",\n  \"details\": \"...\",\n  \"status\": 404\n}\n```\n\n| Field | Always? | Description |\n|---|---|---|\n| `error` | Yes | A short, stable description of the error. Safe to rely on in logs and alerts. |\n| `status` | Yes | The HTTP status code, identical to the response status. |\n| `details` | No | Extra explanation, when available. |\n| `reason` | On 401 | Why authentication failed. See [Authentication & permissions](#description/authentication). |\n| `retry_after` | On 429 | When the next request window opens (ISO 8601). |\n| `code` | Sometimes | A database error code, when it is safe to expose: on 400 (e.g. `23514` for a status the organization does not define), on 409 (`23505`, a duplicate value) and on 500. |\n\nSome errors add context fields, for example `existing_link_id` when you try to link a contact that is already linked to the file.\n\n## Status codes\n\n| Status | Meaning | What to do |\n|---|---|---|\n| `400 Bad Request` | Invalid body (malformed JSON or not an object), a missing required field, an invalid value (for example an unknown status, a malformed ID, or an ID that belongs to another organization), or an update with no updatable field | Fix the request. Don't retry it as is. |\n| `401 Unauthorized` | API key missing, invalid, expired or revoked | Check `reason` |\n| `403 Forbidden` | The key lacks permission for this action on this resource | Add the permission to the key |\n| `404 Not Found` | The record doesn't exist, was deleted or belongs to another organization - or the route isn't supported | Check the ID and the path |\n| `405 Method Not Allowed` | The HTTP method isn't supported on this route | Check which methods the endpoint supports |\n| `409 Conflict` | The action conflicts with the current state: an existing link, a locked note, a cancelled payment, or a duplicate unique value (such as an ID number) | Read the current record and decide how to proceed |\n| `429 Too Many Requests` | Rate limit exceeded | Wait until `retry_after`. See [Rate limits](#description/rate-limits). |\n| `500 Internal Server Error` | A failure on banta's side | Retry with exponential backoff; contact support if it persists. |\n\n> The API also returns `404` for a record that exists in another organization, so an ID can't be probed for existence.\n\n## Retries\n\n- **Retry:** `429`, `500`, and network errors or timeouts. Use exponential backoff (e.g. 1, 2, 4, 8 seconds) with some jitter.\n- **Don't retry without changing something:** `400`, `401`, `403`, `404`, `405`, `409`.\n- **Careful with `POST` after a timeout:** the first request may have succeeded. The API doesn't support idempotency keys yet, so before re-sending a create, check with `search` whether the record already exists.\n\n# Rate limits\n\n## The limit\n\nEach API key is limited to **60 requests per 60-second window**. The window opens with the first request and resets 60 seconds later. The limit applies per key, not per organization.\n\nA request over the limit receives `429 Too Many Requests` and is not executed:\n\n```json\n{\n  \"retry_after\": \"2026-10-14T09:31:00.000Z\",\n  \"error\": \"Too Many Requests\",\n  \"details\": \"Rate limit exceeded (61 requests in window)\",\n  \"status\": 429\n}\n```\n\n`retry_after` is when the next window opens. The API does not send a `Retry-After` header, so read the field from the body.\n\n## Staying within the limit\n\n- **Large pages** - when listing, use `limit=500`. One page of 500 costs the same as one page of 50.\n- **Incremental sync** - for periodic syncs, remember when the last run happened and process only what changed instead of re-fetching everything.\n- **A queue on your side** - if you create many records at once (an import, say), send them from a queue at up to one request per second.\n- **One key per integration** - so load from one system can't block another, and revoking a single integration is easy.\n- **Handle 429** - wait until `retry_after`, then retry.\n\n```js\nasync function bantaFetch(url, init, attempt = 0) {\n  const res = await fetch(url, init)\n  if (res.status !== 429 || attempt >= 3) return res\n  const body = await res.json().catch(() => ({}))\n  const waitMs = body.retry_after\n    ? Math.max(0, new Date(body.retry_after).getTime() - Date.now()) + 250\n    : 2 ** attempt * 1000\n  await new Promise((r) => setTimeout(r, waitMs))\n  return bantaFetch(url, init, attempt + 1)\n}\n```\n\nIf your integration consistently needs a higher rate, contact us at [support@banta.co.il](mailto:support@banta.co.il).\n\n# AI agents & MCP\n\nThere are two ways to work with banta from AI tools:\n\n1. **Let the agent read these docs** so it can write integration code against the API for you. See \"Docs for AI agents\" below.\n2. **Connect the agent directly to your organization's data** through the banta MCP server, so it can search, summarize and take actions itself. See \"Connecting over MCP\".\n\n## Docs for AI agents (LLM version)\n\nAll of this documentation is also published as clean text that language models read easily, and it updates automatically with every API change. English (the default) lives at the site root; Hebrew lives under `/he/`.\n\n| English | Hebrew | Contents |\n|---|---|---|\n| [`/llms.txt`](https://docs.banta.co.il/llms.txt) | [`/he/llms.txt`](https://docs.banta.co.il/he/llms.txt) | Index following [llmstxt.org](https://llmstxt.org): a link to every guide and every endpoint |\n| [`/llms-full.txt`](https://docs.banta.co.il/llms-full.txt) | [`/he/llms-full.txt`](https://docs.banta.co.il/he/llms-full.txt) | The entire documentation in one file: guides and the full reference |\n| `/guides/<slug>.md` | `/he/guides/<slug>.md` | One guide as Markdown, e.g. [`/guides/authentication.md`](https://docs.banta.co.il/guides/authentication.md) |\n| `/reference/<operationId>.md` | `/he/reference/<operationId>.md` | One endpoint as Markdown, e.g. [`/reference/createLead.md`](https://docs.banta.co.il/reference/createLead.md) |\n| [`/openapi.json`](https://docs.banta.co.il/openapi.json) · [`/openapi.yaml`](https://docs.banta.co.il/openapi.yaml) | [`/he/openapi.json`](https://docs.banta.co.il/he/openapi.json) | The full OpenAPI document, for Postman, Insomnia or SDK generators |\n\n**On the site:**\n\n- **Ask AI** (top bar) - opens ChatGPT, Claude or Perplexity with an instruction to read `llms-full.txt`.\n- **Copy as Markdown** (on every endpoint) - copies that endpoint's documentation, ready to paste into a chat.\n\n**For coding agents (Claude Code, Cursor, Copilot)** - add this to your prompt or to your project's instructions file:\n\n```text\nThe banta API reference is at https://docs.banta.co.il/llms.txt (index) and\nhttps://docs.banta.co.il/llms-full.txt (full). Read it before writing integration code.\nAuth: header x-api-key. Base URL: https://app.banta.co.il/api-service\n```\n\n## Connecting over MCP\n\nThe banta MCP server gives AI agents tools for working with your organization's data: searching leads and files, summarizing a deal, creating tasks and reminders, and more. Server URL:\n\n```text\nhttps://db.banta.co.il/functions/v1/mcp-server\n```\n\n### Authentication\n\n- **OAuth (recommended)** - paste the URL into your MCP client. The client sends you to a banta sign-in and consent screen, and everything else is automatic. By default only organization admins can approve a connection. You can open this up to all members, or turn external connections off entirely, in [Organization settings → Integrations → AI](https://app.banta.co.il/organization/settings?group=integrations&tab=ai).\n- **Access token** - for clients that support custom headers. Create a token (it starts with `bnt_mcp_`) on the same settings screen and send it as `Authorization: Bearer <token>`.\n\n### Per client\n\n- **Claude (claude.ai and the Desktop app)** - Settings → Connectors → Add custom connector, paste the server URL and approve on the banta screen.\n- **Claude Code** - `claude mcp add --transport http banta https://db.banta.co.il/functions/v1/mcp-server`\n- **Cursor / VS Code** - the install button in the top bar of this site adds the server in one click.\n- **ChatGPT (GPT Actions)** - in Configure → Actions → Import from URL, import `https://db.banta.co.il/functions/v1/mcp-server/openapi.json`. Under Authentication choose API Key, type Bearer, and paste an access token.\n\n### What an agent can do\n\n- The available tools are set by your organization's policy, and can be narrowed further per token.\n- Sensitive actions (money, status changes and deletions) may require approval by a user in the app. In that case the agent receives `approval_required`, and the action runs only after the request is approved in banta.\n- Every agent call is recorded in the organization's audit log.\n\n# Changelog\n\nChanges to the API, newest first. Breaking changes are marked **[Breaking]** and announced here in advance.\n\n## October 2026\n\n- The public documentation site launched at https://docs.banta.co.il in English and Hebrew, including an LLM version (`llms.txt`, `llms-full.txt` and Markdown per endpoint) and guides for authentication, permissions, pagination, errors and rate limits.\n- The OpenAPI document is now in English and was reconciled with actual behavior: consistent error responses (401/403/404/429/500) on every endpoint, and previously undocumented fields on charges and milestones. Tag names in the spec are now English (for example `Leads`).\n- `GET /api-docs/openapi.json` once again returns the full spec. It had been returning an outdated, abbreviated version.\n- **Security** - IDs sent in request bodies (`customer_id`, `lead_id`, `source_lead_id`, `parent_task_id`, `recipient_user_id`, `charge_id`) are validated against your organization. An ID that belongs to another organization returns 400.\n- **[Breaking] Permissions** - the general `write` permission no longer allows `DELETE`, matching the \"Read & write\" option in the app. Deleting requires `admin`, `resource:*` or `resource:delete`.\n- **Deletes** - `DELETE /mortgage-files/{id}` and `DELETE /customers/{id}` now delete the record. They previously returned success without deleting it.\n- **Statuses** - leads accept the organization's custom statuses. A new mortgage file gets the organization's default status (or `setup`) instead of the invalid `new`. `GET /mortgage-files/statuses` returns the real system statuses, `GET /mortgage-files/{id}/status-history` works, and a file status change saves `notes` as `status_comment`. A lead status change saves `notes` in the status history only and no longer overwrites the lead's notes.\n- **Tasks** - creating tasks works. Status values are `open`, `in_progress`, `completed` and `cancelled` (`done` is accepted as `completed`), and `completed_at` is set and cleared automatically.\n- **Notes** - a locked note can be unlocked with `is_locked: false`.\n- **Errors** - values the database rejects return 400 (duplicates return 409) instead of 500, and `child_errors` contains error codes only.\n- `GET /customers/{id}/mortgage-files` returns `{ data, count }` with the customer's mortgage files.\n\n## August 2026\n\n- **Charges** - a charge can be linked to a milestone with `milestone_id` and `milestone_status_key` (sent together), with an optional `milestone_due_offset_days`. When the milestone is completed, the due date is set automatically. A manually entered due date is never overwritten.\n- **Leads** - `DELETE /leads/{id}` permanently deletes the lead. A deleted lead cannot be restored.\n\n## May 2026\n\n- New endpoints nested under mortgage files: notes, file contacts, watchers, documents, signatures, generated documents, document statuses, reminders, charges, payments, analyses, calculator mixes, custom fields and milestones.\n- Top-level tasks (`/tasks`), linked to a file, a lead or a customer - or standalone.\n- Resource/action permissions (`leads:read` and so on) alongside the general ones.\n\n## April 2026\n\n- Security hardening: keys are stored hashed only, 401 responses explain the `reason`, a rate limit of 60 requests per minute per key, and list pages capped at 500.\n- An audit log entry for every write.\n\n## January 2026\n\n- Contacts (`/contacts`), system lists (`/lists`) and status endpoints for leads and files.\n- Incomes, bank accounts and obligations when creating a mortgage file, and more ID types for borrowers (passport, association, company).",
    "version": "1.0.0",
    "contact": {
      "name": "banta Support",
      "email": "support@banta.co.il",
      "url": "https://app.banta.co.il"
    }
  },
  "servers": [
    {
      "url": "https://app.banta.co.il",
      "description": "Production"
    }
  ],
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "An API key sent in the `x-api-key` header with every request.\n\n**Creating a key:** In the app, go to Organization settings → API keys. The full key is shown only once, when it is created. Each key belongs to a single organization, and all of its requests read and write only that organization's data. A revoked or expired key is rejected with 401.\n\n**Permissions:** Each key has a list of permissions. Every request is checked against the resource (the first path segment after `/api-service/`) and against the action, which is derived from the HTTP method: `GET` is `read`, `DELETE` is `delete`, and everything else (`POST`, `PUT`, `PATCH`) is `write`. Supported permission formats:\n- `*` or `admin` - full access to all resources.\n- `resource:*` - all actions on a single resource, for example `leads:*`.\n- `resource:action` - a single action on a single resource, for example `tasks:read` or `customers:delete`.\n- `read` / `write` (legacy format) - `read` allows reading all resources; `write` allows creating and updating across all resources, **but not deleting** (deleting requires `admin`, `*`, `resource:*` or `resource:delete`).\n\nResources: `leads`, `mortgage-files`, `customers`, `contacts`, `tasks`, `lists`. All nested paths under `/mortgage-files/{id}/...` (borrowers, file tasks, notes, charges, and so on) are checked against the `mortgage-files` resource. A key without the required permission receives 403."
      }
    },
    "schemas": {
      "Borrower": {
        "type": "object",
        "description": "A borrower on a mortgage file: the record that links a customer to the file (relationship type, order, borrower type), together with the linked customer's details. Customer details (name, identification, contact details, etc.) are stored on the customer record and shared across all files in which that customer is a borrower.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Borrower ID (the record linking the customer to the file)"
          },
          "first_name": {
            "type": "string",
            "description": "First name"
          },
          "last_name": {
            "type": "string",
            "description": "Last name"
          },
          "entity_name": {
            "type": "string",
            "description": "Name of the company or nonprofit association (when id_type is company or association)"
          },
          "id_type": {
            "type": "string",
            "enum": [
              "israeli_id",
              "passport",
              "association",
              "company"
            ],
            "description": "Identification document type"
          },
          "id_number": {
            "type": "string",
            "description": "Identification document number"
          },
          "id_country": {
            "type": "string",
            "description": "Country that issued the identification document (relevant for passports)"
          },
          "issue_date": {
            "type": "string",
            "format": "date",
            "description": "Issue date of the identification document"
          },
          "id_expiry_date": {
            "type": "string",
            "format": "date",
            "description": "Expiration date of the identification document"
          },
          "birth_date": {
            "type": "string",
            "format": "date",
            "description": "Date of birth"
          },
          "gender": {
            "type": "string",
            "enum": [
              "male",
              "female",
              "other"
            ],
            "description": "Gender"
          },
          "marital_status": {
            "type": "string",
            "enum": [
              "single",
              "married",
              "divorced",
              "widowed",
              "separated",
              "domestic_partnership",
              "other"
            ],
            "description": "Marital status"
          },
          "custom_marital_status": {
            "type": "string",
            "description": "Custom marital status (when marital_status=other)"
          },
          "relationship_type": {
            "type": "string",
            "enum": [
              "main",
              "spouse",
              "business_partner",
              "siblings",
              "other"
            ],
            "description": "The borrower's relationship type on the file. A borrower with order_index=0 must be main"
          },
          "custom_relationship": {
            "type": "string",
            "description": "Custom relationship type (when relationship_type=other)"
          },
          "borrower_type": {
            "type": "string",
            "enum": [
              "regular",
              "paying_guarantor",
              "supporting_guarantor",
              "non_mortgaging_borrower"
            ],
            "description": "Borrower type"
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "Email address"
          },
          "phone": {
            "type": "string",
            "description": "Phone number"
          },
          "street": {
            "type": "string",
            "description": "Street of residence"
          },
          "city": {
            "type": "string",
            "description": "City of residence"
          },
          "has_children": {
            "type": "boolean",
            "description": "Whether the borrower has children"
          },
          "children_under_18": {
            "type": "integer",
            "description": "Number of children under 18"
          },
          "children_birth_dates": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "date"
            },
            "description": "Children's dates of birth"
          },
          "has_foreign_citizenship": {
            "type": "boolean",
            "description": "Whether the borrower holds foreign citizenship"
          },
          "foreign_citizenship": {
            "type": "string",
            "description": "Country of foreign citizenship"
          },
          "is_politically_exposed": {
            "type": "boolean",
            "description": "Whether the borrower is a politically exposed person (PEP)"
          },
          "preferred_contact_methods": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "email",
                "sms",
                "whatsapp",
                "voice",
                "no_sms"
              ]
            },
            "description": "Preferred contact methods"
          },
          "spouse_of_borrower_id": {
            "type": "string",
            "format": "uuid",
            "description": "ID of the borrower who is this borrower's spouse (in files with more than 2 borrowers)"
          },
          "customer_id": {
            "type": "string",
            "format": "uuid",
            "description": "ID of the linked customer"
          },
          "order_index": {
            "type": "integer",
            "description": "The borrower's position on the file (0 = main borrower)"
          },
          "mortgage_file_id": {
            "type": "string",
            "format": "uuid",
            "description": "Mortgage file ID"
          },
          "organization_id": {
            "type": "string",
            "format": "uuid",
            "description": "Organization ID"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Creation date"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last updated date"
          }
        }
      },
      "Lead": {
        "type": "object",
        "description": "A lead: an inquiry from a prospective customer. The response may include additional columns that are not documented here.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Lead ID"
          },
          "organization_id": {
            "type": "string",
            "format": "uuid",
            "description": "Organization ID"
          },
          "lead_number": {
            "type": "string",
            "description": "Unique lead number (generated automatically)"
          },
          "first_name": {
            "type": "string",
            "description": "First name"
          },
          "last_name": {
            "type": "string",
            "description": "Last name"
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "Email address"
          },
          "phone": {
            "type": "string",
            "description": "Phone number"
          },
          "source": {
            "type": "string",
            "description": "Lead source. A lead created through the API without a source gets the value api"
          },
          "status": {
            "type": "string",
            "enum": [
              "new",
              "contacted",
              "qualified",
              "converted",
              "lost",
              "custom"
            ],
            "description": "Lead status. custom indicates one of the organization's custom statuses, whose key is stored in status_custom"
          },
          "status_custom": {
            "type": "string",
            "description": "Key of the custom status (when status=custom)",
            "nullable": true
          },
          "notes": {
            "type": "string",
            "description": "General notes"
          },
          "mortgage_purpose": {
            "type": "string",
            "description": "Mortgage purpose (purchase, refinance, renovation, etc.)"
          },
          "required_amount": {
            "type": "number",
            "description": "Required mortgage amount"
          },
          "total_income": {
            "type": "number",
            "description": "Total monthly income of all borrowers"
          },
          "has_property": {
            "type": "boolean",
            "description": "Whether the lead already owns a property"
          },
          "assigned_to": {
            "type": "string",
            "format": "uuid",
            "description": "ID of the user the lead is assigned to (null if unassigned)",
            "nullable": true
          },
          "team_id": {
            "type": "string",
            "format": "uuid",
            "description": "ID of the team the lead belongs to"
          },
          "borrowers_data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LeadBorrower"
            },
            "description": "Details of the prospective borrowers"
          },
          "mortgage_request_data": {
            "type": "object",
            "description": "Mortgage request details",
            "properties": {
              "property_type": {
                "type": "string",
                "description": "Property type"
              },
              "property_value": {
                "type": "number",
                "description": "Property value"
              },
              "property_location": {
                "type": "string",
                "description": "Property location"
              },
              "loan_purpose": {
                "type": "string",
                "description": "Loan purpose"
              }
            }
          },
          "financial_data": {
            "type": "object",
            "description": "Financial details",
            "properties": {
              "monthly_income": {
                "type": "number",
                "description": "Monthly income"
              },
              "existing_obligations": {
                "type": "number",
                "description": "Existing obligations"
              },
              "savings": {
                "type": "number",
                "description": "Savings"
              }
            }
          },
          "additional_details": {
            "type": "object",
            "description": "Additional details (free-form structure)",
            "additionalProperties": true
          },
          "custom_fields_leads": {
            "type": "object",
            "description": "Custom fields defined by the organization",
            "additionalProperties": true
          },
          "converted_to_customer": {
            "type": "string",
            "format": "uuid",
            "description": "ID of the customer the lead was converted to (if converted)"
          },
          "converted_to_mortgage_file_id": {
            "type": "string",
            "format": "uuid",
            "description": "ID of the mortgage file created from the lead (if converted)"
          },
          "utm_source": {
            "type": "string",
            "description": "The utm_source parameter captured with the lead"
          },
          "utm_medium": {
            "type": "string",
            "description": "The utm_medium parameter captured with the lead"
          },
          "utm_campaign": {
            "type": "string",
            "description": "The utm_campaign parameter captured with the lead"
          },
          "utm_term": {
            "type": "string",
            "description": "The utm_term parameter captured with the lead"
          },
          "utm_content": {
            "type": "string",
            "description": "The utm_content parameter captured with the lead"
          },
          "referrer_url": {
            "type": "string",
            "description": "Referrer URL the lead came from"
          },
          "landing_path": {
            "type": "string",
            "description": "Path of the landing page where the lead was captured"
          },
          "status_changed_at": {
            "type": "string",
            "format": "date-time",
            "description": "Date of the last status change"
          },
          "first_response_time": {
            "type": "string",
            "format": "date-time",
            "description": "Time of the first response to the lead"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Creation date"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last updated date"
          },
          "created_by": {
            "type": "string",
            "format": "uuid",
            "description": "ID of the user who created the lead"
          }
        },
        "required": [
          "first_name",
          "last_name",
          "phone"
        ]
      },
      "LeadBorrower": {
        "type": "object",
        "description": "Details of a prospective borrower on a lead",
        "properties": {
          "first_name": {
            "type": "string",
            "description": "First name"
          },
          "last_name": {
            "type": "string",
            "description": "Last name"
          },
          "id_number": {
            "type": "string",
            "description": "Israeli ID number"
          },
          "phone": {
            "type": "string",
            "description": "Phone number"
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "Email address"
          },
          "birth_date": {
            "type": "string",
            "format": "date",
            "description": "Date of birth"
          },
          "relationship_type": {
            "type": "string",
            "enum": [
              "main",
              "spouse",
              "business_partner",
              "co_borrower",
              "guarantor",
              "siblings",
              "other"
            ],
            "description": "Relationship type"
          },
          "marital_status": {
            "type": "string",
            "enum": [
              "single",
              "married",
              "divorced",
              "widowed",
              "separated",
              "domestic_partnership",
              "other"
            ],
            "description": "Marital status"
          },
          "employment_type": {
            "type": "string",
            "description": "Employment type"
          },
          "monthly_income": {
            "type": "number",
            "description": "Monthly income"
          }
        },
        "required": [
          "first_name",
          "last_name"
        ]
      },
      "CreateLead": {
        "type": "object",
        "description": "Data for creating a lead. Fields not listed here are ignored.",
        "properties": {
          "first_name": {
            "type": "string",
            "description": "First name"
          },
          "last_name": {
            "type": "string",
            "description": "Last name"
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "Email address"
          },
          "phone": {
            "type": "string",
            "description": "Phone number"
          },
          "source": {
            "type": "string",
            "description": "Lead source (for example website, facebook, referral)",
            "default": "api"
          },
          "status": {
            "type": "string",
            "description": "Initial status: a system status or one of the organization's custom statuses (see GET /leads/statuses)",
            "default": "new"
          },
          "notes": {
            "type": "string",
            "description": "General notes"
          },
          "mortgage_purpose": {
            "type": "string",
            "description": "Mortgage purpose (purchase, refinance, renovation, etc.)"
          },
          "required_amount": {
            "type": "number",
            "description": "Required mortgage amount"
          },
          "total_income": {
            "type": "number",
            "description": "Total monthly income of all borrowers"
          },
          "has_property": {
            "type": "boolean",
            "description": "Whether the lead already owns a property",
            "default": false
          },
          "assigned_to": {
            "type": "string",
            "format": "uuid",
            "description": "ID of a user in the organization to assign the lead to. An ID that does not belong to an active user in the organization is ignored, and the lead is created unassigned"
          }
        },
        "required": [
          "first_name",
          "last_name",
          "phone"
        ]
      },
      "MortgagePurpose": {
        "type": "object",
        "description": "A mortgage purpose (purchase, refinance, renovation, etc.)",
        "properties": {
          "type": {
            "type": "string",
            "description": "Purpose type - a key from the GET /lists/mortgage-types list (for example second_hand, refinance)"
          },
          "amount": {
            "type": "number",
            "description": "Amount required for this purpose"
          },
          "details": {
            "type": "string",
            "description": "Additional details about the purpose"
          },
          "fields": {
            "type": "object",
            "description": "Detailed fields, depending on the purpose type",
            "properties": {
              "loan_purpose": {
                "type": "string",
                "description": "Detailed loan purpose"
              },
              "tax_declaration": {
                "type": "string",
                "description": "Real estate tax (Mas Shevach) declaration: single apartment, replacement apartment or investment apartment. Values: `GET /api-service/lists/mishach-types`"
              },
              "property_value": {
                "type": "number",
                "description": "Property value"
              },
              "appraiser_value": {
                "type": "number",
                "description": "Property value according to the appraiser"
              },
              "loan_amount": {
                "type": "number",
                "description": "Requested mortgage amount"
              },
              "equity": {
                "type": "number",
                "description": "Equity"
              },
              "eligibility": {
                "type": "number",
                "description": "Eligibility amount"
              },
              "contract_date_payment": {
                "type": "string",
                "description": "Payment date under the contract"
              },
              "mortgage_type": {
                "type": "string",
                "description": "Mortgage type"
              },
              "existing_mortgage": {
                "type": "number",
                "description": "Outstanding balance of the existing mortgage"
              },
              "requested_mortgage": {
                "type": "number",
                "description": "Requested mortgage"
              },
              "monthly_repayment": {
                "type": "number",
                "description": "Monthly repayment"
              },
              "equity_amount": {
                "type": "number",
                "description": "Equity amount"
              },
              "required_date": {
                "type": "string",
                "description": "Date by which the mortgage is needed"
              }
            }
          }
        },
        "required": [
          "type",
          "amount"
        ]
      },
      "MortgageFile": {
        "type": "object",
        "description": "A mortgage file (the file record). The response may include additional internal columns that are not documented here.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "File ID"
          },
          "organization_id": {
            "type": "string",
            "format": "uuid",
            "description": "Organization ID"
          },
          "file_number": {
            "type": "string",
            "description": "File number"
          },
          "title": {
            "type": "string",
            "description": "File title/name"
          },
          "status": {
            "type": "string",
            "description": "Key of the file's status: one of the system statuses (setup, pending_approval, pending_appraisal, reviewing, signing, completed, paused, cancelled, active) or a custom status defined by the organization. See GET /mortgage-files/statuses"
          },
          "status_comment": {
            "type": "string",
            "description": "Comment on the current status"
          },
          "status_changed_at": {
            "type": "string",
            "format": "date-time",
            "description": "Date of the last status change"
          },
          "customer_id": {
            "type": "string",
            "format": "uuid",
            "description": "ID of the file's primary customer"
          },
          "assigned_to": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "ID of the user the file is assigned to (null if unassigned)"
          },
          "purposes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MortgagePurpose"
            },
            "description": "Mortgage purposes"
          },
          "loan_purpose": {
            "type": "string",
            "description": "Loan purpose"
          },
          "loan_amount": {
            "type": "number",
            "description": "Requested mortgage amount"
          },
          "total_amount": {
            "type": "number",
            "description": "Total transaction amount"
          },
          "monthly_payment": {
            "type": "number",
            "description": "Expected monthly repayment"
          },
          "loan_term": {
            "type": "integer",
            "description": "Loan term in months"
          },
          "interest_rate": {
            "type": "number",
            "description": "Average interest rate"
          },
          "property_type": {
            "type": "string",
            "description": "Property type (apartment, private house, plot, etc.)"
          },
          "property_value": {
            "type": "number",
            "description": "Property value per the contract/valuation"
          },
          "property_address": {
            "type": "string",
            "description": "Full property address"
          },
          "appraiser_value": {
            "type": "number",
            "description": "Property value according to the appraiser"
          },
          "equity": {
            "type": "number",
            "description": "Equity"
          },
          "eligibility": {
            "type": "number",
            "description": "Eligibility amount (if applicable)"
          },
          "remaining_mortgage": {
            "type": "number",
            "description": "Outstanding balance of the existing mortgage (for refinancing)"
          },
          "tax_declaration": {
            "type": "string",
            "description": "Real estate tax (Mas Shevach) declaration: single apartment, replacement apartment or investment apartment. Values: `GET /api-service/lists/mishach-types`"
          },
          "contract_date_payment": {
            "type": "string",
            "description": "Payment date under the contract"
          },
          "financing_entity": {
            "allOf": [
              {
                "$ref": "#/components/schemas/FinancingEntity"
              }
            ],
            "description": "Financing entity details (bank)"
          },
          "notes": {
            "type": "string",
            "description": "General notes"
          },
          "additional_info": {
            "allOf": [
              {
                "$ref": "#/components/schemas/MortgageAdditionalInfo"
              }
            ],
            "description": "Extended additional information"
          },
          "additional_expenses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AdditionalExpense"
            },
            "description": "Additional expenses (taxes, legal fees, brokerage fees, etc.)"
          },
          "real_estate_details": {
            "type": "object",
            "description": "Extended real estate details",
            "additionalProperties": true
          },
          "custom_fields_mortgage": {
            "type": "object",
            "description": "Custom fields defined by the organization",
            "additionalProperties": true
          },
          "lead_source": {
            "type": "string",
            "description": "Source of the lead that became this file"
          },
          "source_lead_id": {
            "type": "string",
            "format": "uuid",
            "description": "ID of the original lead (if converted from a lead)"
          },
          "source_lead_number": {
            "type": "string",
            "description": "Number of the original lead"
          },
          "lead_id": {
            "type": "string",
            "format": "uuid",
            "description": "ID of a linked lead"
          },
          "drive_folder_url": {
            "type": "string",
            "description": "Link to the Google Drive folder"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Creation date"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last updated date"
          },
          "created_by": {
            "type": "string",
            "format": "uuid",
            "description": "ID of the user who created the file"
          }
        }
      },
      "FinancingEntity": {
        "type": "object",
        "description": "Financing entity details (bank)",
        "properties": {
          "bank_name": {
            "type": "string",
            "description": "Bank name"
          },
          "branch_number": {
            "type": "string",
            "description": "Branch number"
          },
          "branch_name": {
            "type": "string",
            "description": "Branch name"
          },
          "contact_name": {
            "type": "string",
            "description": "Name of the contact person at the bank"
          },
          "contact_phone": {
            "type": "string",
            "description": "Contact person's phone number"
          },
          "contact_email": {
            "type": "string",
            "format": "email",
            "description": "Contact person's email address"
          }
        }
      },
      "MortgageAdditionalInfo": {
        "type": "object",
        "description": "Additional information about a mortgage file",
        "properties": {
          "general_notes": {
            "type": "string",
            "description": "General notes"
          },
          "important_info": {
            "type": "object",
            "description": "Important information",
            "properties": {
              "payment_day": {
                "type": "integer",
                "description": "Day of the month on which payments are made"
              },
              "equity_sources": {
                "type": "string",
                "description": "Sources of equity"
              },
              "has_grace_period": {
                "type": "boolean",
                "description": "Whether there is a grace period"
              },
              "grace_period_months": {
                "type": "integer",
                "description": "Length of the grace period in months"
              },
              "credit_report_status": {
                "type": "string",
                "description": "Credit report status"
              },
              "has_financial_issues": {
                "type": "boolean",
                "description": "Whether there are financial issues"
              },
              "financial_issues_details": {
                "type": "string",
                "description": "Details of the financial issues"
              },
              "requested_monthly_payment": {
                "type": "number",
                "description": "Requested monthly repayment"
              }
            }
          }
        }
      },
      "AdditionalExpense": {
        "type": "object",
        "description": "An additional expense associated with the transaction",
        "properties": {
          "type": {
            "type": "string",
            "description": "Expense type (purchase tax, legal fees, brokerage fees, etc.)"
          },
          "amount": {
            "type": "number",
            "description": "Expense amount"
          },
          "description": {
            "type": "string",
            "description": "Additional description"
          }
        },
        "required": [
          "type",
          "amount"
        ]
      },
      "BorrowerIncome": {
        "type": "object",
        "description": "A borrower's income data",
        "properties": {
          "borrowerId": {
            "type": "string",
            "format": "uuid",
            "description": "Borrower ID"
          },
          "borrowerName": {
            "type": "string",
            "description": "Borrower name"
          },
          "employments": {
            "type": "array",
            "description": "List of employment/income sources",
            "items": {
              "$ref": "#/components/schemas/EmploymentItem"
            }
          }
        }
      },
      "EmploymentItem": {
        "type": "object",
        "description": "An employment/income item",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "salaried",
              "self_employed",
              "pension",
              "allowance",
              "scholarship",
              "other",
              "unemployed"
            ],
            "description": "Employment type (salaried employee, self-employed, pension, allowance, scholarship, other, not employed)"
          },
          "data": {
            "type": "object",
            "description": "Employment details, depending on the type",
            "properties": {
              "employers": {
                "type": "array",
                "description": "List of employers (for salaried employees)",
                "items": {
                  "type": "object",
                  "properties": {
                    "company_name": {
                      "type": "string",
                      "description": "Company name"
                    },
                    "position": {
                      "type": "string",
                      "description": "Job title"
                    },
                    "start_date": {
                      "type": "string",
                      "format": "date",
                      "description": "Employment start date"
                    },
                    "is_current": {
                      "type": "boolean",
                      "description": "Whether this is the current employer"
                    },
                    "end_date": {
                      "type": "string",
                      "format": "date",
                      "description": "Employment end date"
                    },
                    "salary_slips": {
                      "type": "array",
                      "description": "Pay slips",
                      "items": {
                        "type": "object",
                        "properties": {
                          "date": {
                            "type": "string",
                            "description": "Pay slip date"
                          },
                          "amount": {
                            "type": "string",
                            "description": "Amount"
                          }
                        }
                      }
                    }
                  }
                }
              },
              "is_public_sector": {
                "type": "boolean",
                "description": "Whether the employer is in the public sector"
              },
              "is_controlling_employee": {
                "type": "boolean",
                "description": "Whether the employee is a controlling shareholder"
              },
              "business_name": {
                "type": "string",
                "description": "Business name (for self-employed)"
              },
              "business_type": {
                "type": "string",
                "description": "Business type"
              },
              "years_active": {
                "type": "number",
                "description": "Years in business"
              },
              "average_monthly_income": {
                "type": "string",
                "description": "Average monthly income"
              },
              "monthly_amount": {
                "type": "string",
                "description": "Monthly amount (for a pension/allowance)"
              },
              "source": {
                "type": "string",
                "description": "Income source"
              },
              "scholarship_amount": {
                "type": "string",
                "description": "Scholarship amount"
              },
              "institution": {
                "type": "string",
                "description": "Institution awarding the scholarship"
              },
              "description": {
                "type": "string",
                "description": "Description (for other income)"
              },
              "amount": {
                "type": "string",
                "description": "Amount"
              }
            }
          }
        }
      },
      "Incomes": {
        "type": "object",
        "description": "Income data for a mortgage file",
        "properties": {
          "borrowers": {
            "type": "array",
            "description": "Income by borrower",
            "items": {
              "$ref": "#/components/schemas/BorrowerIncome"
            }
          }
        }
      },
      "BankAccount": {
        "type": "object",
        "description": "A bank account",
        "properties": {
          "bankName": {
            "type": "string",
            "description": "Bank name (code)"
          },
          "bankDisplayName": {
            "type": "string",
            "description": "Bank display name"
          },
          "branchName": {
            "type": "string",
            "description": "Branch number"
          },
          "branchDisplayName": {
            "type": "string",
            "description": "Branch name"
          },
          "accountNumber": {
            "type": "string",
            "description": "Account number"
          },
          "borrowers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs/names of the borrowers associated with the account"
          },
          "isJoint": {
            "type": "boolean",
            "description": "Whether this is a joint account"
          }
        },
        "required": [
          "bankName",
          "branchName",
          "accountNumber"
        ]
      },
      "Obligation": {
        "type": "object",
        "description": "A financial obligation",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique obligation ID"
          },
          "type": {
            "type": "string",
            "enum": [
              "bank_loan",
              "non_bank_loan",
              "mortgage",
              "alimony",
              "rent",
              "other"
            ],
            "description": "Obligation type (bank loan, non-bank loan, mortgage, alimony, rent, other)"
          },
          "customType": {
            "type": "string",
            "description": "Custom type (when type=other)"
          },
          "monthlyPayment": {
            "type": "number",
            "description": "Monthly payment"
          },
          "remainingAmount": {
            "type": "number",
            "description": "Outstanding balance"
          },
          "endDate": {
            "type": "string",
            "format": "date",
            "description": "End date"
          },
          "bank_id": {
            "type": "string",
            "description": "Bank ID (for bank loans)"
          },
          "bankData": {
            "type": "object",
            "description": "Bank details",
            "properties": {
              "bankName": {
                "type": "string",
                "description": "Bank code"
              },
              "bankDisplayName": {
                "type": "string",
                "description": "Bank name"
              },
              "branchName": {
                "type": "string",
                "description": "Branch number"
              },
              "branchDisplayName": {
                "type": "string",
                "description": "Branch name"
              },
              "accountNumber": {
                "type": "string",
                "description": "Account number"
              }
            }
          },
          "assignedBorrowers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of the borrowers the obligation belongs to"
          }
        },
        "required": [
          "type",
          "monthlyPayment"
        ]
      },
      "CreateMortgageFile": {
        "type": "object",
        "description": "Data for creating a mortgage file. No fields are required. Fields not listed here are ignored.",
        "properties": {
          "file_number": {
            "type": "string",
            "description": "File number. The API does not assign a number automatically - if omitted, the file is created without a number"
          },
          "title": {
            "type": "string",
            "description": "File title/name"
          },
          "status": {
            "type": "string",
            "description": "A valid status key in the organization (a system status or a custom status). If omitted, the API sets new - see the operation description",
            "default": "new"
          },
          "status_comment": {
            "type": "string",
            "description": "Comment on the current status"
          },
          "customer_id": {
            "type": "string",
            "format": "uuid",
            "description": "ID of the file's primary customer (optional)"
          },
          "assigned_to": {
            "type": "string",
            "format": "uuid",
            "description": "ID of a user in the organization to assign the file to. An ID that does not belong to an active user in the organization is ignored, and the file is created unassigned"
          },
          "borrowers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CreateBorrower"
            },
            "description": "Borrowers to create together with the file. Each item is handled like POST /mortgage-files/{id}/borrowers; the first defaults to relationship_type=main and the rest to spouse"
          },
          "purposes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MortgagePurpose"
            },
            "description": "Mortgage purposes (default: an empty array)"
          },
          "loan_purpose": {
            "type": "string",
            "description": "Loan purpose"
          },
          "loan_amount": {
            "type": "number",
            "description": "Requested mortgage amount"
          },
          "total_amount": {
            "type": "number",
            "description": "Total transaction amount"
          },
          "monthly_payment": {
            "type": "number",
            "description": "Expected monthly repayment"
          },
          "loan_term": {
            "type": "integer",
            "description": "Loan term in months"
          },
          "interest_rate": {
            "type": "number",
            "description": "Average interest rate"
          },
          "property_type": {
            "type": "string",
            "description": "Property type (apartment, private house, plot, etc.)"
          },
          "property_value": {
            "type": "number",
            "description": "Property value"
          },
          "property_address": {
            "type": "string",
            "description": "Full property address"
          },
          "appraiser_value": {
            "type": "number",
            "description": "Property value according to the appraiser"
          },
          "equity": {
            "type": "number",
            "description": "Equity"
          },
          "eligibility": {
            "type": "number",
            "description": "Eligibility amount"
          },
          "remaining_mortgage": {
            "type": "number",
            "description": "Outstanding balance of the existing mortgage (for refinancing)"
          },
          "tax_declaration": {
            "type": "string",
            "description": "Real estate tax (Mas Shevach) declaration: single apartment, replacement apartment or investment apartment. Values: `GET /api-service/lists/mishach-types`"
          },
          "contract_date_payment": {
            "type": "string",
            "description": "Payment date under the contract"
          },
          "financing_entity": {
            "allOf": [
              {
                "$ref": "#/components/schemas/FinancingEntity"
              }
            ],
            "description": "Financing entity details (bank)"
          },
          "notes": {
            "type": "string",
            "description": "General notes"
          },
          "additional_info": {
            "allOf": [
              {
                "$ref": "#/components/schemas/MortgageAdditionalInfo"
              }
            ],
            "description": "Extended additional information"
          },
          "additional_expenses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AdditionalExpense"
            },
            "description": "Additional expenses"
          },
          "real_estate_details": {
            "type": "object",
            "description": "Extended real estate details",
            "additionalProperties": true
          },
          "custom_fields_mortgage": {
            "type": "object",
            "description": "Custom fields",
            "additionalProperties": true
          },
          "lead_source": {
            "type": "string",
            "description": "Lead source"
          },
          "lead_id": {
            "type": "string",
            "format": "uuid",
            "description": "ID of a linked lead"
          },
          "source_lead_id": {
            "type": "string",
            "format": "uuid",
            "description": "ID of the original lead the file was created from"
          },
          "source_lead_number": {
            "type": "string",
            "description": "Number of the original lead"
          },
          "incomes": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Incomes"
              }
            ],
            "description": "The borrowers' income data. Stored as sent"
          },
          "bank_accounts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BankAccount"
            },
            "description": "The borrowers' bank accounts. Stored as sent"
          },
          "obligations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Obligation"
            },
            "description": "The borrowers' financial obligations. Stored as sent"
          }
        }
      },
      "CreateBorrower": {
        "type": "object",
        "description": "Data for adding a borrower to a file. Customer fields (name, identification, contact details, etc.) are saved to the customer record, and only when id_number is sent - see the description of the POST /mortgage-files/{id}/borrowers operation.",
        "properties": {
          "first_name": {
            "type": "string",
            "description": "First name (required when a new customer is created)"
          },
          "last_name": {
            "type": "string",
            "description": "Last name (required when a new customer is created)"
          },
          "entity_name": {
            "type": "string",
            "description": "Name of the company or nonprofit association (when id_type is company or association)"
          },
          "id_type": {
            "type": "string",
            "enum": [
              "israeli_id",
              "passport",
              "association",
              "company"
            ],
            "description": "Identification document type. For a new customer, defaults to israeli_id"
          },
          "id_number": {
            "type": "string",
            "description": "Identification document number. Used to find an existing customer in the organization or to create a new customer"
          },
          "id_country": {
            "type": "string",
            "description": "Country that issued the identification document (relevant for passports)"
          },
          "issue_date": {
            "type": "string",
            "format": "date",
            "description": "Issue date of the identification document"
          },
          "id_expiry_date": {
            "type": "string",
            "format": "date",
            "description": "Expiration date of the identification document"
          },
          "birth_date": {
            "type": "string",
            "format": "date",
            "description": "Date of birth"
          },
          "gender": {
            "type": "string",
            "enum": [
              "male",
              "female",
              "other"
            ],
            "description": "Gender"
          },
          "marital_status": {
            "type": "string",
            "enum": [
              "single",
              "married",
              "divorced",
              "widowed",
              "separated",
              "domestic_partnership",
              "other"
            ],
            "description": "Marital status"
          },
          "custom_marital_status": {
            "type": "string",
            "description": "Custom marital status (when marital_status=other)"
          },
          "relationship_type": {
            "type": "string",
            "enum": [
              "main",
              "spouse",
              "business_partner",
              "siblings",
              "other"
            ],
            "description": "Relationship type on the file. Default: main for the first borrower on the file, spouse for subsequent borrowers. A borrower with order_index=0 must be main"
          },
          "custom_relationship": {
            "type": "string",
            "description": "Custom relationship type (when relationship_type=other)"
          },
          "borrower_type": {
            "type": "string",
            "enum": [
              "regular",
              "paying_guarantor",
              "supporting_guarantor",
              "non_mortgaging_borrower"
            ],
            "description": "Borrower type",
            "default": "regular"
          },
          "order_index": {
            "type": "integer",
            "description": "The borrower's position on the file (0 = main borrower). Default: the number of borrowers already on the file"
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "Email address"
          },
          "phone": {
            "type": "string",
            "description": "Phone number"
          },
          "street": {
            "type": "string",
            "description": "Street of residence"
          },
          "city": {
            "type": "string",
            "description": "City of residence"
          },
          "has_children": {
            "type": "boolean",
            "description": "Whether the borrower has children"
          },
          "children_under_18": {
            "type": "integer",
            "description": "Number of children under 18"
          },
          "children_birth_dates": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "date"
            },
            "description": "Children's dates of birth"
          },
          "has_foreign_citizenship": {
            "type": "boolean",
            "description": "Whether the borrower holds foreign citizenship"
          },
          "foreign_citizenship": {
            "type": "string",
            "description": "Country of foreign citizenship"
          },
          "is_politically_exposed": {
            "type": "boolean",
            "description": "Whether the borrower is a politically exposed person (PEP)"
          },
          "preferred_contact_methods": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "email",
                "sms",
                "whatsapp",
                "voice",
                "no_sms"
              ]
            },
            "description": "Preferred contact methods"
          },
          "customer_id": {
            "type": "string",
            "format": "uuid",
            "description": "ID of an existing customer to link. Used only when id_number is not sent"
          }
        }
      },
      "UpdateMortgageStatus": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "description": "Key of the new status: a system status or one of the organization's custom statuses (see GET /mortgage-files/statuses)"
          },
          "notes": {
            "type": "string",
            "description": "Comment on the status change (optional). Saved as the file's status_comment"
          }
        },
        "required": [
          "status"
        ]
      },
      "Customer": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Customer ID"
          },
          "organization_id": {
            "type": "string",
            "format": "uuid",
            "description": "Organization ID"
          },
          "first_name": {
            "type": "string",
            "description": "First name"
          },
          "last_name": {
            "type": "string",
            "description": "Last name"
          },
          "entity_name": {
            "type": "string",
            "description": "Name of the company or nonprofit association (when id_type is company or association)"
          },
          "id_type": {
            "type": "string",
            "enum": [
              "israeli_id",
              "passport",
              "association",
              "company"
            ],
            "description": "Identification document type"
          },
          "id_number": {
            "type": "string",
            "description": "Identification document number"
          },
          "id_country": {
            "type": "string",
            "description": "Country that issued the identification document (relevant for passports)"
          },
          "issue_date": {
            "type": "string",
            "format": "date",
            "description": "Issue date of the identification document"
          },
          "id_expiry_date": {
            "type": "string",
            "format": "date",
            "description": "Expiration date of the identification document"
          },
          "phone": {
            "type": "string",
            "description": "Phone number"
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "Email address"
          },
          "birth_date": {
            "type": "string",
            "format": "date",
            "description": "Date of birth"
          },
          "gender": {
            "type": "string",
            "enum": [
              "male",
              "female",
              "other"
            ],
            "description": "Gender"
          },
          "marital_status": {
            "type": "string",
            "enum": [
              "single",
              "married",
              "divorced",
              "widowed",
              "separated",
              "domestic_partnership",
              "other"
            ],
            "description": "Marital status"
          },
          "custom_marital_status": {
            "type": "string",
            "description": "Custom marital status (when marital_status=other)"
          },
          "street": {
            "type": "string",
            "description": "Street"
          },
          "city": {
            "type": "string",
            "description": "City"
          },
          "has_children": {
            "type": "boolean",
            "description": "Whether the customer has children"
          },
          "children_under_18": {
            "type": "integer",
            "description": "Number of children under 18"
          },
          "children_birth_dates": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "date"
            },
            "description": "Children's dates of birth"
          },
          "has_foreign_citizenship": {
            "type": "boolean",
            "description": "Whether the customer holds foreign citizenship"
          },
          "foreign_citizenship": {
            "type": "string",
            "description": "Country of foreign citizenship"
          },
          "is_politically_exposed": {
            "type": "boolean",
            "description": "Whether the customer is a politically exposed person (PEP)"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Creation date"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last updated date"
          },
          "mortgage_files": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MortgageFile"
            },
            "description": "Returned only by GET /customers/{id}: the active mortgage files in which this customer is the primary customer (customer_id), without borrowers"
          }
        },
        "required": [
          "first_name",
          "last_name"
        ],
        "description": "A customer in the organization. The response may include additional columns that are not documented here."
      },
      "CreateCustomer": {
        "type": "object",
        "properties": {
          "first_name": {
            "type": "string",
            "description": "First name"
          },
          "last_name": {
            "type": "string",
            "description": "Last name"
          },
          "entity_name": {
            "type": "string",
            "description": "Name of the company or nonprofit association (when id_type is company or association)"
          },
          "id_type": {
            "type": "string",
            "enum": [
              "israeli_id",
              "passport",
              "association",
              "company"
            ],
            "description": "Identification document type",
            "default": "israeli_id"
          },
          "id_number": {
            "type": "string",
            "description": "Identification document number. Unique within the organization - if a customer with the same number already exists, 409 is returned"
          },
          "id_country": {
            "type": "string",
            "description": "Country that issued the identification document (relevant for passports)"
          },
          "issue_date": {
            "type": "string",
            "format": "date",
            "description": "Issue date of the identification document"
          },
          "id_expiry_date": {
            "type": "string",
            "format": "date",
            "description": "Expiration date of the identification document"
          },
          "phone": {
            "type": "string",
            "description": "Phone number"
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "Email address"
          },
          "birth_date": {
            "type": "string",
            "format": "date",
            "description": "Date of birth"
          },
          "gender": {
            "type": "string",
            "enum": [
              "male",
              "female",
              "other"
            ],
            "description": "Gender"
          },
          "marital_status": {
            "type": "string",
            "enum": [
              "single",
              "married",
              "divorced",
              "widowed",
              "separated",
              "domestic_partnership",
              "other"
            ],
            "description": "Marital status"
          },
          "custom_marital_status": {
            "type": "string",
            "description": "Custom marital status (when marital_status=other)"
          },
          "street": {
            "type": "string",
            "description": "Street"
          },
          "city": {
            "type": "string",
            "description": "City"
          },
          "has_children": {
            "type": "boolean",
            "description": "Whether the customer has children"
          },
          "children_under_18": {
            "type": "integer",
            "description": "Number of children under 18"
          },
          "children_birth_dates": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "date"
            },
            "description": "Children's dates of birth"
          },
          "has_foreign_citizenship": {
            "type": "boolean",
            "description": "Whether the customer holds foreign citizenship"
          },
          "foreign_citizenship": {
            "type": "string",
            "description": "Country of foreign citizenship"
          },
          "is_politically_exposed": {
            "type": "boolean",
            "description": "Whether the customer is a politically exposed person (PEP)"
          }
        },
        "required": [
          "first_name",
          "last_name"
        ],
        "description": "Data for creating a customer. Fields not listed here are ignored."
      },
      "ErrorResponse": {
        "type": "object",
        "description": "A consistent structure for all error responses. In addition to the fixed error and status fields, some errors add context fields - for example validation, existing_customer_id, related_files_count, related_mortgages_count, existing_link_id, existing_id, provided_type, or available_lists.",
        "properties": {
          "error": {
            "type": "string",
            "description": "Short description of the error (in English)"
          },
          "details": {
            "type": "string",
            "description": "Additional details, when available. Never includes raw database messages"
          },
          "status": {
            "type": "integer",
            "description": "HTTP status code (same as the response code)"
          },
          "reason": {
            "type": "string",
            "enum": [
              "missing_api_key",
              "malformed_api_key",
              "invalid_api_key",
              "auth_service_error"
            ],
            "description": "401 only: the reason the key was rejected"
          },
          "retry_after": {
            "type": "string",
            "format": "date-time",
            "description": "429 only: when the rate-limit window resets"
          },
          "code": {
            "type": "string",
            "description": "The PostgREST/Postgres error code, when it is safe to expose: on 400 (22P02, 23503, 23514), 409 (23505) and 500"
          },
          "validation": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "On 400 for missing required fields: a map from each field name to the message \"Required field\""
          }
        },
        "required": [
          "error",
          "status"
        ],
        "additionalProperties": true
      },
      "TimelineEvent": {
        "type": "object",
        "description": "A timeline event (file created, status changed, etc.)",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "organization_id": {
            "type": "string",
            "format": "uuid"
          },
          "entity_type": {
            "type": "string",
            "example": "mortgage_file"
          },
          "entity_id": {
            "type": "string",
            "format": "uuid"
          },
          "event_type": {
            "type": "string",
            "description": "Event type (for example status_updated, note_added, task_created, file_created)"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "metadata": {
            "type": "object",
            "description": "Type-specific metadata (old_status/new_status, etc.)"
          },
          "created_by": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Task": {
        "type": "object",
        "description": "A task. It can be linked to a mortgage file, a lead, or a customer, or be standalone (all *_id fields can be null). The response includes an object for the linked entity (`mortgage_file`/`lead`/`customer`) when one exists.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "organization_id": {
            "type": "string",
            "format": "uuid"
          },
          "mortgage_file_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "lead_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "customer_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "in_progress",
              "completed",
              "cancelled"
            ]
          },
          "priority": {
            "type": "string",
            "enum": [
              "low",
              "medium",
              "high"
            ]
          },
          "due_date": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Due date"
          },
          "assigned_to": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "parent_task_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "progress": {
            "type": "number",
            "minimum": 0,
            "maximum": 100,
            "description": "Progress percentage"
          },
          "is_favorite": {
            "type": "boolean"
          },
          "completed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "completed_by": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "mortgage_file": {
            "nullable": true,
            "description": "Details of the linked file (null if not linked)",
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "file_number": {
                "type": "string",
                "nullable": true
              },
              "title": {
                "type": "string",
                "nullable": true
              },
              "status": {
                "type": "string",
                "nullable": true
              }
            }
          },
          "lead": {
            "nullable": true,
            "description": "Details of the linked lead (null if not linked)",
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "first_name": {
                "type": "string",
                "nullable": true
              },
              "last_name": {
                "type": "string",
                "nullable": true
              },
              "phone": {
                "type": "string",
                "nullable": true
              },
              "status": {
                "type": "string",
                "nullable": true
              }
            }
          },
          "customer": {
            "nullable": true,
            "description": "Details of the linked customer (null if not linked)",
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "first_name": {
                "type": "string",
                "nullable": true
              },
              "last_name": {
                "type": "string",
                "nullable": true
              },
              "id_number": {
                "type": "string",
                "nullable": true
              }
            }
          }
        }
      },
      "CreateTask": {
        "type": "object",
        "description": "Data for creating a task. You can link the task to a file, a lead, and/or a customer, or leave all three IDs empty to create a standalone task. Fields not listed here are ignored.",
        "properties": {
          "title": {
            "type": "string",
            "description": "Task title (required, must not be empty)"
          },
          "description": {
            "type": "string"
          },
          "due_date": {
            "type": "string",
            "format": "date-time",
            "description": "Due date (ISO 8601)"
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "in_progress",
              "completed",
              "cancelled"
            ],
            "default": "open"
          },
          "priority": {
            "type": "string",
            "enum": [
              "low",
              "medium",
              "high"
            ],
            "default": "medium"
          },
          "assigned_to": {
            "type": "string",
            "format": "uuid",
            "description": "ID of a user in the organization. An ID that does not belong to an active user in the organization is ignored, and the task is created unassigned"
          },
          "parent_task_id": {
            "type": "string",
            "format": "uuid",
            "description": "ID of the parent task (for a subtask)"
          },
          "progress": {
            "type": "number",
            "minimum": 0,
            "maximum": 100,
            "description": "Progress percentage"
          },
          "is_favorite": {
            "type": "boolean"
          },
          "mortgage_file_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "File to link. On the /mortgage-files/{id}/tasks path, it is taken from the path and the value here is ignored"
          },
          "lead_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "Lead to link. Ignored on the /mortgage-files/{id}/tasks path"
          },
          "customer_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "Customer to link. Ignored on the /mortgage-files/{id}/tasks path"
          }
        },
        "required": [
          "title"
        ]
      },
      "UpdateTask": {
        "type": "object",
        "description": "A partial update of a task: only the fields that are sent are updated. Replacing or unlinking (null) the linked entity is supported only via PUT/PATCH /tasks/{taskId}; on the /mortgage-files/{id}/tasks/{taskId} path, these fields are ignored.",
        "properties": {
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "due_date": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Due date (ISO 8601)"
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "in_progress",
              "completed",
              "cancelled"
            ]
          },
          "priority": {
            "type": "string",
            "enum": [
              "low",
              "medium",
              "high"
            ]
          },
          "assigned_to": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "ID of a user in the organization. null or an empty string removes the assignment; an ID that does not belong to an active user in the organization is ignored"
          },
          "parent_task_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "ID of the parent task"
          },
          "progress": {
            "type": "number",
            "minimum": 0,
            "maximum": 100,
            "description": "Progress percentage"
          },
          "is_favorite": {
            "type": "boolean"
          },
          "mortgage_file_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "File to link (null unlinks it). Must be an active file in the organization"
          },
          "lead_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "Lead to link (null unlinks it). Must be a lead in the organization"
          },
          "customer_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "Customer to link (null unlinks it). Must be an active customer in the organization"
          }
        }
      },
      "Note": {
        "type": "object",
        "description": "A note on a mortgage file (entity_notes)",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "organization_id": {
            "type": "string",
            "format": "uuid"
          },
          "entity_type": {
            "type": "string",
            "example": "mortgage_file"
          },
          "entity_id": {
            "type": "string",
            "format": "uuid"
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "content": {
            "type": "string"
          },
          "is_pinned": {
            "type": "boolean"
          },
          "is_locked": {
            "type": "boolean",
            "description": "A locked note can be updated only in a request that also unlocks it (is_locked: false)"
          },
          "is_completed": {
            "type": "boolean"
          },
          "completed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "CreateNote": {
        "type": "object",
        "properties": {
          "content": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "is_pinned": {
            "type": "boolean",
            "default": false
          },
          "is_locked": {
            "type": "boolean",
            "default": false
          },
          "is_completed": {
            "type": "boolean",
            "default": false
          }
        },
        "required": [
          "content"
        ],
        "description": "Data for creating a note. content is required."
      },
      "UpdateNote": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "content": {
            "type": "string"
          },
          "is_pinned": {
            "type": "boolean"
          },
          "is_locked": {
            "type": "boolean"
          },
          "is_completed": {
            "type": "boolean"
          }
        }
      },
      "MortgageContactLink": {
        "type": "object",
        "description": "A link between a contact and a file (mortgage_contacts)",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "organization_id": {
            "type": "string",
            "format": "uuid"
          },
          "mortgage_file_id": {
            "type": "string",
            "format": "uuid"
          },
          "contact_id": {
            "type": "string",
            "format": "uuid"
          },
          "notes": {
            "type": "string",
            "nullable": true
          },
          "contact": {
            "type": "object",
            "description": "Contact details (joined)",
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "first_name": {
                "type": "string"
              },
              "last_name": {
                "type": "string"
              },
              "type": {
                "type": "string"
              },
              "custom_type": {
                "type": "string",
                "nullable": true
              },
              "email": {
                "type": "string",
                "nullable": true
              },
              "phone": {
                "type": "string",
                "nullable": true
              },
              "company": {
                "type": "string",
                "nullable": true
              },
              "job_title": {
                "type": "string",
                "nullable": true
              }
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Watcher": {
        "type": "object",
        "description": "A user who watches a file (mortgage_file_watchers). Note: `email` is not available through the external API (the email address is stored in auth.users, separately from profiles).",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "organization_id": {
            "type": "string",
            "format": "uuid"
          },
          "mortgage_file_id": {
            "type": "string",
            "format": "uuid"
          },
          "watcher_id": {
            "type": "string",
            "format": "uuid"
          },
          "watcher": {
            "type": "object",
            "description": "User details (joined from profiles)",
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "first_name": {
                "type": "string"
              },
              "last_name": {
                "type": "string"
              }
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ClientDocument": {
        "type": "object",
        "description": "A customer document (metadata only; the content is stored in Supabase Storage)",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "organization_id": {
            "type": "string",
            "format": "uuid"
          },
          "mortgage_file_id": {
            "type": "string",
            "format": "uuid"
          },
          "borrower_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "original_name": {
            "type": "string"
          },
          "stored_name": {
            "type": "string"
          },
          "file_path": {
            "type": "string"
          },
          "file_size": {
            "type": "integer",
            "nullable": true
          },
          "file_type": {
            "type": "string",
            "nullable": true
          },
          "category": {
            "type": "string",
            "nullable": true
          },
          "needs_signature": {
            "type": "boolean"
          },
          "uploaded_by_type": {
            "type": "string",
            "enum": [
              "borrower",
              "advisor"
            ]
          },
          "uploaded_by_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "drive_folder_id": {
            "type": "string",
            "nullable": true
          },
          "drive_file_id": {
            "type": "string",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "DocumentSignature": {
        "type": "object",
        "description": "A signature on a document",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "organization_id": {
            "type": "string",
            "format": "uuid"
          },
          "document_id": {
            "type": "string",
            "format": "uuid"
          },
          "borrower_id": {
            "type": "string",
            "format": "uuid"
          },
          "is_signed": {
            "type": "boolean"
          },
          "signed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "signature_date": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "document": {
            "type": "object",
            "description": "Document details (joined)",
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "original_name": {
                "type": "string"
              },
              "mortgage_file_id": {
                "type": "string",
                "format": "uuid"
              },
              "borrower_id": {
                "type": "string",
                "format": "uuid",
                "nullable": true
              },
              "file_path": {
                "type": "string"
              }
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "GeneratedDocument": {
        "type": "object",
        "description": "A document generated from a template (generated_documents)",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "organization_id": {
            "type": "string",
            "format": "uuid"
          },
          "template_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "entity_type": {
            "type": "string",
            "example": "mortgage_file"
          },
          "entity_id": {
            "type": "string",
            "format": "uuid"
          },
          "document_name": {
            "type": "string"
          },
          "filled_content": {
            "type": "string",
            "nullable": true
          },
          "filled_variables": {
            "type": "object"
          },
          "signatures": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "pdf_path": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ClientDocumentStatus": {
        "type": "object",
        "description": "Status of a required document, per borrower",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "organization_id": {
            "type": "string",
            "format": "uuid"
          },
          "mortgage_file_id": {
            "type": "string",
            "format": "uuid"
          },
          "borrower_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "document_type_id": {
            "type": "string"
          },
          "document_type_title": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "uploading",
              "under_review",
              "completed",
              "rejected"
            ]
          },
          "uploaded_document_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "upload_progress": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100
          },
          "notes": {
            "type": "object",
            "description": "Document metadata, including status_history"
          },
          "hide_from_client": {
            "type": "boolean"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Reminder": {
        "type": "object",
        "description": "A reminder on a file (reminders)",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "organization_id": {
            "type": "string",
            "format": "uuid"
          },
          "entity_type": {
            "type": "string",
            "example": "mortgage_file"
          },
          "entity_id": {
            "type": "string",
            "format": "uuid"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "remind_at": {
            "type": "string",
            "format": "date-time"
          },
          "channels": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "notification",
              "email"
            ]
          },
          "metadata": {
            "type": "object"
          },
          "recipient_user_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "ID of the user who receives the reminder. Must be a user in the organization"
          },
          "is_sent": {
            "type": "boolean"
          },
          "sent_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "is_dismissed": {
            "type": "boolean"
          },
          "dismissed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CreateReminder": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "remind_at": {
            "type": "string",
            "format": "date-time"
          },
          "channels": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "metadata": {
            "type": "object"
          },
          "recipient_user_id": {
            "type": "string",
            "format": "uuid",
            "description": "ID of the user who receives the reminder. Must be a user in the organization"
          }
        },
        "required": [
          "title",
          "remind_at"
        ]
      },
      "UpdateReminder": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "remind_at": {
            "type": "string",
            "format": "date-time"
          },
          "channels": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "metadata": {
            "type": "object"
          },
          "recipient_user_id": {
            "type": "string",
            "format": "uuid",
            "description": "ID of the user who receives the reminder. Must be a user in the organization"
          },
          "is_dismissed": {
            "type": "boolean"
          }
        }
      },
      "MortgageCharge": {
        "type": "object",
        "description": "A charge (payment request) on a file. The response may include additional payment-processing integration columns that are not documented here.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "organization_id": {
            "type": "string",
            "format": "uuid"
          },
          "mortgage_file_id": {
            "type": "string",
            "format": "uuid"
          },
          "item_name": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "amount": {
            "type": "number"
          },
          "includes_vat": {
            "type": "boolean"
          },
          "is_ancillary_charge": {
            "type": "boolean",
            "description": "true = an ancillary charge (for example a Land Registry (Tabu) extract or courier fees); false = a advisory fee"
          },
          "due_date": {
            "type": "string",
            "format": "date",
            "nullable": true,
            "description": "Collection date. For a charge linked to a milestone, it may be set automatically - see due_date_source"
          },
          "due_date_source": {
            "type": "string",
            "enum": [
              "manual",
              "milestone"
            ],
            "readOnly": true,
            "description": "Source of the collection date (set by the system): manual - entered manually and never overwritten automatically; milestone - set automatically when the linked milestone is completed"
          },
          "milestone_id": {
            "type": "string",
            "nullable": true,
            "description": "ID of the milestone the charge is linked to (an ID from the organization's milestone configuration, or the ID of a file-specific custom milestone). Always sent together with milestone_status_key"
          },
          "milestone_status_key": {
            "type": "string",
            "nullable": true,
            "description": "Key of the status that the linked milestone belongs to. Always sent together with milestone_id"
          },
          "milestone_due_offset_days": {
            "type": "integer",
            "description": "Number of days after the milestone is completed on which the collection date is set (0 = the completion date)"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "partial",
              "paid",
              "cancelled"
            ]
          },
          "notes": {
            "type": "string",
            "nullable": true
          },
          "external_document_id": {
            "type": "string",
            "nullable": true,
            "description": "When set, the charge is locked for editing"
          },
          "external_document_number": {
            "type": "string",
            "nullable": true
          },
          "external_document_type": {
            "type": "string",
            "nullable": true
          },
          "external_document_url": {
            "type": "string",
            "nullable": true
          },
          "external_provider": {
            "type": "string",
            "nullable": true
          },
          "document_is_cancelled": {
            "type": "boolean"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CreateMortgageCharge": {
        "type": "object",
        "properties": {
          "item_name": {
            "type": "string",
            "description": "Item name (required, non-empty)"
          },
          "description": {
            "type": "string"
          },
          "amount": {
            "type": "number",
            "minimum": 0,
            "description": "Amount (a non-negative number)"
          },
          "includes_vat": {
            "type": "boolean",
            "default": true,
            "description": "Whether the amount includes VAT"
          },
          "is_ancillary_charge": {
            "type": "boolean",
            "description": "true = ancillary charge (e.g. a Land Registry (Tabu) extract or courier fees); false = advisory fee",
            "default": false
          },
          "due_date": {
            "type": "string",
            "format": "date",
            "description": "Collection date (YYYY-MM-DD)"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "partial",
              "paid",
              "cancelled"
            ],
            "default": "pending"
          },
          "notes": {
            "type": "string"
          },
          "milestone_id": {
            "type": "string",
            "description": "ID of the milestone to link. Must be sent together with milestone_status_key"
          },
          "milestone_status_key": {
            "type": "string",
            "description": "Status key of the milestone. Must be sent together with milestone_id"
          },
          "milestone_due_offset_days": {
            "type": "integer",
            "description": "Number of days after the milestone is completed on which the collection date is set (0 = the completion date)",
            "default": 0
          }
        },
        "required": [
          "item_name",
          "amount"
        ],
        "description": "Data for creating a charge. milestone_id and milestone_status_key must be sent together or not at all; otherwise the request returns 400."
      },
      "UpdateMortgageCharge": {
        "type": "object",
        "properties": {
          "item_name": {
            "type": "string",
            "description": "Item name"
          },
          "description": {
            "type": "string"
          },
          "amount": {
            "type": "number",
            "description": "Amount"
          },
          "includes_vat": {
            "type": "boolean",
            "description": "Whether the amount includes VAT"
          },
          "is_ancillary_charge": {
            "type": "boolean",
            "description": "true = ancillary charge (e.g. a Land Registry (Tabu) extract or courier fees); false = advisory fee"
          },
          "due_date": {
            "type": "string",
            "format": "date",
            "description": "Collection date (YYYY-MM-DD). Updating it through the API marks it as manual (due_date_source=manual)"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "partial",
              "paid",
              "cancelled"
            ]
          },
          "notes": {
            "type": "string"
          },
          "milestone_id": {
            "type": "string",
            "nullable": true,
            "description": "ID of the milestone to link. Setting both link fields to null removes the link"
          },
          "milestone_status_key": {
            "type": "string",
            "nullable": true,
            "description": "Status key of the milestone. Setting both link fields to null removes the link"
          },
          "milestone_due_offset_days": {
            "type": "integer",
            "description": "Number of days after the milestone is completed on which the collection date is set (0 = the completion date)"
          }
        },
        "description": "Partial update of a charge. The milestone-link pairing rule is evaluated against the merged result (the stored values combined with the request); otherwise the request returns 400."
      },
      "MortgagePayment": {
        "type": "object",
        "description": "A payment received (mortgage_payments)",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "organization_id": {
            "type": "string",
            "format": "uuid"
          },
          "mortgage_file_id": {
            "type": "string",
            "format": "uuid"
          },
          "charge_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "amount": {
            "type": "number"
          },
          "payment_date": {
            "type": "string",
            "format": "date"
          },
          "payment_source": {
            "type": "string"
          },
          "payment_method": {
            "type": "string",
            "nullable": true
          },
          "reference_number": {
            "type": "string",
            "nullable": true
          },
          "receipt_number": {
            "type": "string",
            "nullable": true
          },
          "notes": {
            "type": "string",
            "nullable": true
          },
          "is_cancelled": {
            "type": "boolean"
          },
          "cancelled_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "external_document_id": {
            "type": "string",
            "nullable": true,
            "description": "When set, the payment is locked for editing"
          },
          "external_document_number": {
            "type": "string",
            "nullable": true
          },
          "external_document_url": {
            "type": "string",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CreateMortgagePayment": {
        "type": "object",
        "properties": {
          "charge_id": {
            "type": "string",
            "format": "uuid",
            "description": "Optional: the specific charge this payment is for"
          },
          "amount": {
            "type": "number",
            "minimum": 0,
            "exclusiveMinimum": true,
            "description": "Payment amount (a positive number)"
          },
          "payment_date": {
            "type": "string",
            "format": "date"
          },
          "payment_source": {
            "type": "string"
          },
          "payment_method": {
            "type": "string"
          },
          "reference_number": {
            "type": "string"
          },
          "receipt_number": {
            "type": "string"
          },
          "notes": {
            "type": "string"
          }
        },
        "required": [
          "amount",
          "payment_date",
          "payment_source"
        ]
      },
      "UpdateMortgagePayment": {
        "type": "object",
        "properties": {
          "charge_id": {
            "type": "string",
            "format": "uuid",
            "description": "The charge this payment is associated with"
          },
          "amount": {
            "type": "number",
            "description": "Payment amount"
          },
          "payment_date": {
            "type": "string",
            "format": "date"
          },
          "payment_source": {
            "type": "string"
          },
          "payment_method": {
            "type": "string"
          },
          "reference_number": {
            "type": "string"
          },
          "receipt_number": {
            "type": "string"
          },
          "notes": {
            "type": "string"
          }
        }
      },
      "MortgageAnalysis": {
        "type": "object",
        "description": "A saved file analysis (mortgage_analysis)",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "organization_id": {
            "type": "string",
            "format": "uuid"
          },
          "mortgage_file_id": {
            "type": "string",
            "format": "uuid"
          },
          "analysis_data": {
            "type": "object",
            "description": "Analysis content (free-form jsonb)"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CalculatorMix": {
        "type": "object",
        "description": "A mix saved from the calculator (calculator_mixes)",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "organization_id": {
            "type": "string",
            "format": "uuid"
          },
          "mortgage_file_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "lead_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "data": {
            "type": "object",
            "description": "Loan track breakdown (jsonb)"
          },
          "source": {
            "type": "string",
            "enum": [
              "internal",
              "smartnpv"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CreateCalculatorMix": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "data": {
            "type": "object"
          },
          "source": {
            "type": "string",
            "enum": [
              "internal",
              "smartnpv"
            ],
            "default": "internal"
          }
        },
        "required": [
          "name"
        ]
      },
      "UpdateCalculatorMix": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "data": {
            "type": "object"
          },
          "source": {
            "type": "string",
            "enum": [
              "internal",
              "smartnpv"
            ]
          }
        }
      },
      "CustomFieldWithValue": {
        "type": "object",
        "description": "A custom field definition plus its value for the current file",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Field definition ID"
          },
          "organization_id": {
            "type": "string",
            "format": "uuid"
          },
          "entity_type": {
            "type": "string",
            "enum": [
              "leads",
              "mortgage_files",
              "customers",
              "contacts"
            ]
          },
          "field_name": {
            "type": "string"
          },
          "field_label": {
            "type": "string"
          },
          "field_type": {
            "type": "string",
            "enum": [
              "text",
              "number",
              "email",
              "tel",
              "url",
              "password",
              "textarea",
              "rich_text",
              "checkbox",
              "radio",
              "switch",
              "select",
              "date",
              "datetime",
              "time",
              "currency",
              "multi_select"
            ]
          },
          "field_options": {
            "type": "object",
            "nullable": true
          },
          "is_required": {
            "type": "boolean"
          },
          "display_order": {
            "type": "integer"
          },
          "value": {
            "type": "string",
            "nullable": true,
            "description": "The field's current value for the file (null if not set)"
          }
        }
      },
      "CustomFieldValue": {
        "type": "object",
        "description": "A custom field value (custom_field_values)",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "organization_id": {
            "type": "string",
            "format": "uuid"
          },
          "custom_field_id": {
            "type": "string",
            "format": "uuid"
          },
          "entity_id": {
            "type": "string",
            "format": "uuid"
          },
          "field_value": {
            "type": "string",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CustomFileMilestone": {
        "type": "object",
        "description": "A custom milestone on a file (custom_file_milestones)",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "organization_id": {
            "type": "string",
            "format": "uuid"
          },
          "mortgage_file_id": {
            "type": "string",
            "format": "uuid"
          },
          "status_key": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "is_required": {
            "type": "boolean"
          },
          "bg_color": {
            "type": "string",
            "nullable": true
          },
          "text_color": {
            "type": "string",
            "nullable": true
          },
          "linked_type": {
            "type": "string",
            "nullable": true,
            "description": "Source of the milestone's progress: none, client_documents, client_signatures, or checklist"
          },
          "due_date_type": {
            "type": "string",
            "nullable": true,
            "description": "How the due date is calculated: none, days, hours, specific_date, days_after_milestone, or days_before_required_date"
          },
          "due_date_value": {
            "type": "integer",
            "nullable": true,
            "description": "Number of days or hours, according to due_date_type"
          },
          "due_date_specific": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "due_date_after_milestone_id": {
            "type": "string",
            "nullable": true
          },
          "custom_order": {
            "type": "integer",
            "nullable": true
          },
          "checklist_items": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "CreateCustomFileMilestone": {
        "type": "object",
        "properties": {
          "status_key": {
            "type": "string",
            "description": "Key of the status the milestone belongs to"
          },
          "label": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "is_required": {
            "type": "boolean",
            "default": false
          },
          "bg_color": {
            "type": "string"
          },
          "text_color": {
            "type": "string"
          },
          "linked_type": {
            "type": "string",
            "description": "Source of the milestone's progress: none, client_documents, client_signatures, or checklist"
          },
          "due_date_type": {
            "type": "string",
            "description": "How the due date is calculated: none, days, hours, specific_date, days_after_milestone, or days_before_required_date"
          },
          "due_date_value": {
            "type": "integer",
            "description": "Number of days or hours, according to due_date_type"
          },
          "due_date_specific": {
            "type": "string",
            "format": "date-time"
          },
          "due_date_after_milestone_id": {
            "type": "string"
          },
          "custom_order": {
            "type": "integer"
          },
          "checklist_items": {
            "type": "array",
            "items": {
              "type": "object"
            }
          }
        },
        "required": [
          "status_key",
          "label"
        ],
        "description": "Data for creating a custom milestone. status_key and label are required."
      },
      "UpdateCustomFileMilestone": {
        "type": "object",
        "properties": {
          "status_key": {
            "type": "string",
            "description": "Key of the status the milestone belongs to"
          },
          "label": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "is_required": {
            "type": "boolean"
          },
          "bg_color": {
            "type": "string"
          },
          "text_color": {
            "type": "string"
          },
          "linked_type": {
            "type": "string",
            "description": "Source of the milestone's progress: none, client_documents, client_signatures, or checklist"
          },
          "due_date_type": {
            "type": "string",
            "description": "How the due date is calculated: none, days, hours, specific_date, days_after_milestone, or days_before_required_date"
          },
          "due_date_value": {
            "type": "integer",
            "description": "Number of days or hours, according to due_date_type"
          },
          "due_date_specific": {
            "type": "string",
            "format": "date-time"
          },
          "due_date_after_milestone_id": {
            "type": "string"
          },
          "custom_order": {
            "type": "integer"
          },
          "checklist_items": {
            "type": "array",
            "items": {
              "type": "object"
            }
          }
        },
        "description": "Partial update of a custom milestone."
      },
      "MilestoneProgress": {
        "type": "object",
        "description": "Progress on a milestone (mortgage_milestone_progress)",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "organization_id": {
            "type": "string",
            "format": "uuid"
          },
          "mortgage_file_id": {
            "type": "string",
            "format": "uuid"
          },
          "status_key": {
            "type": "string"
          },
          "milestone_id": {
            "type": "string"
          },
          "is_completed": {
            "type": "boolean"
          },
          "completion_percentage": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100
          },
          "completed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "completed_by": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "due_date": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "due_date_override": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "notes": {
            "type": "string",
            "nullable": true
          },
          "custom_order": {
            "type": "integer",
            "nullable": true
          },
          "carried_to_status_key": {
            "type": "string",
            "nullable": true,
            "description": "If the progress was carried over to another status, the key of that status"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "UpdateMilestoneProgress": {
        "type": "object",
        "properties": {
          "is_completed": {
            "type": "boolean"
          },
          "completion_percentage": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100
          },
          "due_date_override": {
            "type": "string",
            "format": "date-time"
          },
          "notes": {
            "type": "string"
          },
          "custom_order": {
            "type": "integer"
          }
        }
      },
      "MilestoneChecklistItem": {
        "type": "object",
        "description": "A checklist item on a milestone",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "organization_id": {
            "type": "string",
            "format": "uuid"
          },
          "mortgage_file_id": {
            "type": "string",
            "format": "uuid"
          },
          "milestone_id": {
            "type": "string"
          },
          "status_key": {
            "type": "string",
            "nullable": true
          },
          "template_item_id": {
            "type": "string",
            "nullable": true
          },
          "label": {
            "type": "string"
          },
          "sort_order": {
            "type": "integer"
          },
          "is_completed": {
            "type": "boolean"
          },
          "completed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "completed_by": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "UpdateMilestoneChecklistItem": {
        "type": "object",
        "properties": {
          "label": {
            "type": "string"
          },
          "sort_order": {
            "type": "integer"
          },
          "is_completed": {
            "type": "boolean"
          }
        }
      },
      "MilestonesOverview": {
        "type": "object",
        "description": "Combined view of a file's milestones (definitions + progress + checklists)",
        "properties": {
          "data": {
            "type": "array",
            "description": "The organization's statuses, each with its list of milestones (system + custom)",
            "items": {
              "type": "object",
              "properties": {
                "key": {
                  "type": "string",
                  "description": "Status identifier (setup, pending, etc.)"
                },
                "label": {
                  "type": "string",
                  "nullable": true
                },
                "bgColor": {
                  "type": "string",
                  "nullable": true
                },
                "textColor": {
                  "type": "string",
                  "nullable": true
                },
                "is_locked": {
                  "type": "boolean"
                },
                "is_hidden": {
                  "type": "boolean"
                },
                "order": {
                  "type": "integer",
                  "nullable": true
                },
                "milestones": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "description": "A milestone, either system or custom (is_custom=true), with its linked progress and checklist",
                    "properties": {
                      "id": {
                        "type": "string"
                      },
                      "label": {
                        "type": "string"
                      },
                      "description": {
                        "type": "string",
                        "nullable": true
                      },
                      "order": {
                        "type": "integer",
                        "nullable": true
                      },
                      "is_required": {
                        "type": "boolean"
                      },
                      "is_custom": {
                        "type": "boolean",
                        "description": "true → source: custom_file_milestones; false → source: organization_settings"
                      },
                      "progress": {
                        "type": "object",
                        "nullable": true,
                        "description": "Row from mortgage_milestone_progress (null if not created yet)"
                      },
                      "checklist": {
                        "type": "array",
                        "items": {
                          "type": "object"
                        },
                        "description": "Checklist items linked to this milestone"
                      }
                    }
                  }
                }
              }
            }
          },
          "count": {
            "type": "integer",
            "description": "Number of statuses in the response"
          },
          "summary": {
            "type": "object",
            "properties": {
              "total_milestones": {
                "type": "integer"
              },
              "total_custom": {
                "type": "integer"
              },
              "total_progress_rows": {
                "type": "integer"
              },
              "total_checklist_items": {
                "type": "integer"
              },
              "truncated": {
                "type": "boolean",
                "description": "true if any of the queries exceeded the hard_cap limit and the result was truncated"
              },
              "hard_cap": {
                "type": "integer",
                "description": "Maximum number of rows retrieved from each table (2000)"
              }
            }
          }
        }
      },
      "RequiredDocumentsOverview": {
        "type": "object",
        "description": "Combined view of required documents (definitions + statuses)",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "categories": {
                "type": "array",
                "description": "Document categories defined by the organization",
                "items": {
                  "type": "object",
                  "additionalProperties": true
                }
              },
              "documents": {
                "type": "array",
                "description": "Document definitions. Each document is enriched with statuses[], the client_document_status rows already created for it",
                "items": {
                  "type": "object",
                  "additionalProperties": true,
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "categoryId": {
                      "type": "string"
                    },
                    "category_name": {
                      "type": "string",
                      "nullable": true,
                      "description": "Category name, included for convenience"
                    },
                    "isRequired": {
                      "type": "boolean"
                    },
                    "requirement": {
                      "type": "string",
                      "enum": [
                        "per_borrower",
                        "all_borrowers",
                        "per_account_owner"
                      ]
                    },
                    "conditions": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "statuses": {
                      "type": "array",
                      "description": "Rows from client_document_status (one per borrower) for this document. Empty if none have been created yet.",
                      "items": {
                        "$ref": "#/components/schemas/ClientDocumentStatus"
                      }
                    }
                  }
                }
              }
            }
          },
          "summary": {
            "type": "object",
            "properties": {
              "total_categories": {
                "type": "integer"
              },
              "total_documents": {
                "type": "integer"
              },
              "total_status_rows": {
                "type": "integer"
              },
              "truncated": {
                "type": "boolean",
                "description": "true if any of the queries exceeded the hard_cap limit and the result was truncated"
              },
              "hard_cap": {
                "type": "integer",
                "description": "Maximum number of rows retrieved from each table (2000)"
              }
            }
          }
        }
      },
      "ListItem": {
        "type": "object",
        "description": "An item in a basic list",
        "properties": {
          "key": {
            "type": "string",
            "description": "Item identifier"
          },
          "label": {
            "type": "string",
            "description": "Display name in Hebrew"
          }
        },
        "required": [
          "key",
          "label"
        ]
      },
      "StatusListItem": {
        "type": "object",
        "description": "An item in a status list, with colors",
        "properties": {
          "key": {
            "type": "string",
            "description": "Status identifier"
          },
          "label": {
            "type": "string",
            "description": "Display name in Hebrew"
          },
          "bgColor": {
            "type": "string",
            "description": "Background color (HEX)"
          },
          "textColor": {
            "type": "string",
            "description": "Text color (HEX)"
          }
        },
        "required": [
          "key",
          "label",
          "bgColor",
          "textColor"
        ]
      },
      "CalendarEventTypeItem": {
        "type": "object",
        "description": "A calendar event type",
        "properties": {
          "code": {
            "type": "string",
            "description": "Event type identifier"
          },
          "name": {
            "type": "string",
            "description": "Name in Hebrew"
          },
          "nameEn": {
            "type": "string",
            "description": "Name in English"
          },
          "color": {
            "type": "string",
            "description": "Event color (HEX)"
          },
          "icon": {
            "type": "string",
            "description": "Icon name"
          },
          "sortOrder": {
            "type": "integer",
            "description": "Sort order"
          },
          "showInCalendar": {
            "type": "boolean",
            "description": "Whether the event type is shown in the calendar"
          },
          "allowSync": {
            "type": "boolean",
            "description": "Whether syncing is allowed"
          }
        },
        "required": [
          "code",
          "name",
          "color"
        ]
      },
      "ListResponse": {
        "type": "object",
        "description": "Basic list response",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ListItem"
            },
            "description": "List items"
          },
          "count": {
            "type": "integer",
            "description": "Number of items"
          },
          "list_type": {
            "type": "string",
            "description": "List type"
          }
        }
      },
      "StatusListResponse": {
        "type": "object",
        "description": "Status list response",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/StatusListItem"
            },
            "description": "List items"
          },
          "count": {
            "type": "integer",
            "description": "Number of items"
          },
          "list_type": {
            "type": "string",
            "description": "List type"
          }
        }
      },
      "CalendarEventTypeListResponse": {
        "type": "object",
        "description": "Calendar event type list response",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CalendarEventTypeItem"
            },
            "description": "Event types"
          },
          "count": {
            "type": "integer",
            "description": "Number of types"
          },
          "list_type": {
            "type": "string",
            "description": "List type"
          }
        }
      },
      "LeadStatus": {
        "type": "object",
        "description": "A lead status, including the organization's custom statuses",
        "properties": {
          "value": {
            "type": "string",
            "description": "Status identifier (key)"
          },
          "label": {
            "type": "string",
            "description": "Display name in Hebrew"
          },
          "color": {
            "type": "object",
            "properties": {
              "bg": {
                "type": "string",
                "description": "Background color (HEX)"
              },
              "text": {
                "type": "string",
                "description": "Text color (HEX)"
              }
            }
          },
          "is_default": {
            "type": "boolean",
            "description": "Whether this is the default status"
          }
        }
      },
      "MortgageStatus": {
        "type": "object",
        "description": "A mortgage file status, including the organization's custom statuses",
        "properties": {
          "key": {
            "type": "string",
            "description": "Status identifier"
          },
          "label": {
            "type": "string",
            "description": "Display name in Hebrew"
          },
          "bgColor": {
            "type": "string",
            "description": "Background color (HEX)"
          },
          "textColor": {
            "type": "string",
            "description": "Text color (HEX)"
          },
          "is_system": {
            "type": "boolean",
            "description": "Whether this is a system status (cannot be deleted)"
          },
          "is_hidden": {
            "type": "boolean",
            "description": "Whether the status is hidden"
          },
          "order": {
            "type": "integer",
            "description": "Display order"
          }
        }
      },
      "Contact": {
        "type": "object",
        "description": "An organization contact (banker, lawyer, appraiser, etc.)",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "organization_id": {
            "type": "string",
            "format": "uuid"
          },
          "first_name": {
            "type": "string",
            "description": "First name"
          },
          "last_name": {
            "type": "string",
            "description": "Last name"
          },
          "phone": {
            "type": "string",
            "description": "Phone"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "company": {
            "type": "string",
            "description": "Company or organization"
          },
          "job_title": {
            "type": "string",
            "description": "Job title"
          },
          "type": {
            "type": "string",
            "enum": [
              "banker",
              "lawyer",
              "appraiser",
              "insurance",
              "contractor",
              "other"
            ],
            "description": "Contact type. When other, details can be given in custom_type"
          },
          "custom_type": {
            "type": "string",
            "description": "Custom type when type = other",
            "nullable": true
          },
          "notes": {
            "type": "string",
            "description": "Notes"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CreateContact": {
        "type": "object",
        "required": [
          "first_name",
          "last_name",
          "type"
        ],
        "properties": {
          "first_name": {
            "type": "string"
          },
          "last_name": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "company": {
            "type": "string"
          },
          "job_title": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "banker",
              "lawyer",
              "appraiser",
              "insurance",
              "contractor",
              "other"
            ],
            "description": "Contact type. When other, details can be given in custom_type"
          },
          "custom_type": {
            "type": "string"
          },
          "notes": {
            "type": "string"
          }
        },
        "description": "Data for creating a contact. first_name, last_name, and type are required."
      },
      "UpdateContact": {
        "type": "object",
        "description": "Partial update of a contact (all fields are optional)",
        "properties": {
          "first_name": {
            "type": "string"
          },
          "last_name": {
            "type": "string"
          },
          "phone": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "company": {
            "type": "string"
          },
          "job_title": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "banker",
              "lawyer",
              "appraiser",
              "insurance",
              "contractor",
              "other"
            ],
            "description": "Contact type. When other, details can be given in custom_type"
          },
          "custom_type": {
            "type": "string"
          },
          "notes": {
            "type": "string"
          }
        }
      },
      "UpdateLead": {
        "type": "object",
        "description": "Partial update of a lead: only the fields sent are updated. Fields not listed here are ignored.",
        "properties": {
          "first_name": {
            "type": "string",
            "description": "First name"
          },
          "last_name": {
            "type": "string",
            "description": "Last name"
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "Email address"
          },
          "phone": {
            "type": "string",
            "description": "Phone number"
          },
          "source": {
            "type": "string",
            "description": "Lead source"
          },
          "status": {
            "type": "string",
            "description": "Lead status: a system status or one of the organization's custom statuses (see GET /leads/statuses). For a status change that is recorded in the status history, use PATCH /leads/{id}/status"
          },
          "notes": {
            "type": "string",
            "description": "General notes"
          },
          "mortgage_purpose": {
            "type": "string",
            "description": "Mortgage purpose (purchase, refinance, renovation, etc.)"
          },
          "required_amount": {
            "type": "number",
            "description": "Required mortgage amount"
          },
          "total_income": {
            "type": "number",
            "description": "Total monthly income of all borrowers"
          },
          "has_property": {
            "type": "boolean",
            "description": "Whether the lead already owns a property"
          },
          "assigned_to": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "ID of a user in the organization. null or an empty string removes the assignment; an ID that does not belong to an active user in the organization is ignored"
          }
        }
      },
      "MortgageFileDetails": {
        "description": "A mortgage file together with its active borrowers",
        "allOf": [
          {
            "$ref": "#/components/schemas/MortgageFile"
          },
          {
            "type": "object",
            "properties": {
              "borrowers": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Borrower"
                },
                "description": "The file's active borrowers"
              }
            }
          }
        ]
      },
      "MortgageFileCreateResult": {
        "description": "File creation response: the file record together with the results of creating the borrowers, incomes, bank accounts, and obligations",
        "allOf": [
          {
            "$ref": "#/components/schemas/MortgageFile"
          },
          {
            "type": "object",
            "properties": {
              "borrowers": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/BorrowerBase"
                },
                "description": "The borrower link records that were created, without customer details. For full details, retrieve the file or /borrowers"
              },
              "incomes": {
                "type": "object",
                "nullable": true,
                "description": "The saved income data (Incomes structure), or null if it was not sent or saving failed"
              },
              "bank_accounts": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/BankAccount"
                },
                "nullable": true,
                "description": "The saved bank accounts, or null"
              },
              "obligations": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Obligation"
                },
                "nullable": true,
                "description": "The saved obligations, or null"
              },
              "child_errors": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Present only when saving a related entity failed (the file itself was saved). Each item has the form `<entity>: <error code>`, for example `borrower[1]: invalid_customer_id`, `borrower[0]: 23502` or `incomes: 23514`."
              }
            }
          }
        ]
      },
      "MortgageFileUpdateResult": {
        "description": "File update response: the updated file record (without borrowers) together with the results of saving the incomes, bank accounts, and obligations",
        "allOf": [
          {
            "$ref": "#/components/schemas/MortgageFile"
          },
          {
            "type": "object",
            "properties": {
              "incomes": {
                "type": "object",
                "nullable": true,
                "description": "The saved income data, or null if incomes was not sent in the request"
              },
              "bank_accounts": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/BankAccount"
                },
                "nullable": true,
                "description": "The stored bank accounts, or null if neither bank_accounts nor obligations was sent in the request"
              },
              "obligations": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Obligation"
                },
                "nullable": true,
                "description": "The stored obligations, or null if neither bank_accounts nor obligations was sent in the request"
              },
              "child_errors": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Present only when saving a related entity failed (the file itself was saved). Each item has the form `<entity>: <error code>`, for example `borrower[1]: invalid_customer_id`, `borrower[0]: 23502` or `incomes: 23514`."
              }
            }
          }
        ]
      },
      "UpdateMortgageFile": {
        "type": "object",
        "description": "Partial update of a file: only the fields sent are updated. Borrowers cannot be updated through this endpoint. Fields not listed here are ignored.",
        "properties": {
          "file_number": {
            "type": "string",
            "description": "File number"
          },
          "title": {
            "type": "string",
            "description": "File title or name"
          },
          "status": {
            "type": "string",
            "description": "A valid status key in the organization. To change the status, using PATCH /mortgage-files/{id}/status is recommended"
          },
          "status_comment": {
            "type": "string",
            "description": "Comment on the current status"
          },
          "customer_id": {
            "type": "string",
            "format": "uuid",
            "description": "ID of the file's primary customer"
          },
          "assigned_to": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "ID of a user in the organization. null or an empty string removes the assignment; an ID that does not belong to an active user in the organization is ignored"
          },
          "purposes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MortgagePurpose"
            },
            "description": "Mortgage purposes (replaces the stored array)"
          },
          "loan_purpose": {
            "type": "string",
            "description": "Loan purpose"
          },
          "loan_amount": {
            "type": "number",
            "description": "Requested mortgage amount"
          },
          "total_amount": {
            "type": "number",
            "description": "Total transaction amount"
          },
          "monthly_payment": {
            "type": "number",
            "description": "Expected monthly payment"
          },
          "loan_term": {
            "type": "integer",
            "description": "Loan term in months"
          },
          "interest_rate": {
            "type": "number",
            "description": "Average interest rate"
          },
          "property_type": {
            "type": "string",
            "description": "Property type (apartment, private house, plot, etc.)"
          },
          "property_value": {
            "type": "number",
            "description": "Property value"
          },
          "property_address": {
            "type": "string",
            "description": "Full property address"
          },
          "appraiser_value": {
            "type": "number",
            "description": "Property value as assessed by the appraiser"
          },
          "equity": {
            "type": "number",
            "description": "Equity"
          },
          "eligibility": {
            "type": "number",
            "description": "Eligibility amount"
          },
          "remaining_mortgage": {
            "type": "number",
            "description": "Remaining balance of the existing mortgage (for refinancing)"
          },
          "tax_declaration": {
            "type": "string",
            "description": "Real estate tax (Mas Shevach) declaration: single apartment, replacement apartment or investment apartment. Values: `GET /api-service/lists/mishach-types`"
          },
          "contract_date_payment": {
            "type": "string",
            "description": "Payment date under the contract"
          },
          "financing_entity": {
            "allOf": [
              {
                "$ref": "#/components/schemas/FinancingEntity"
              }
            ],
            "description": "Financing entity details (bank)"
          },
          "notes": {
            "type": "string",
            "description": "General notes"
          },
          "additional_info": {
            "allOf": [
              {
                "$ref": "#/components/schemas/MortgageAdditionalInfo"
              }
            ],
            "description": "Extended additional information"
          },
          "additional_expenses": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AdditionalExpense"
            },
            "description": "Ancillary expenses"
          },
          "real_estate_details": {
            "type": "object",
            "description": "Extended real estate details",
            "additionalProperties": true
          },
          "custom_fields_mortgage": {
            "type": "object",
            "description": "Custom fields",
            "additionalProperties": true
          },
          "lead_source": {
            "type": "string",
            "description": "Lead source"
          },
          "lead_id": {
            "type": "string",
            "format": "uuid",
            "description": "Linked lead ID"
          },
          "source_lead_id": {
            "type": "string",
            "format": "uuid",
            "description": "ID of the original lead the file was created from"
          },
          "source_lead_number": {
            "type": "string",
            "description": "Number of the original lead"
          },
          "incomes": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Incomes"
              }
            ],
            "description": "Income data. Replaces the stored value"
          },
          "bank_accounts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BankAccount"
            },
            "description": "Bank accounts. Replaces the stored value; the stored obligations are unchanged if not sent"
          },
          "obligations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Obligation"
            },
            "description": "Obligations. Replaces the stored value; the stored bank_accounts are unchanged if not sent"
          }
        }
      },
      "UpdateBorrower": {
        "type": "object",
        "description": "Partial update of a borrower. Customer fields update the linked customer record (and apply to all of that customer's files); link fields (relationship_type, custom_relationship, borrower_type, preferred_contact_methods, order_index) apply only to the borrower in this file.",
        "properties": {
          "first_name": {
            "type": "string",
            "description": "First name"
          },
          "last_name": {
            "type": "string",
            "description": "Last name"
          },
          "entity_name": {
            "type": "string",
            "description": "Name of the company or nonprofit association (when id_type is company or association)"
          },
          "id_type": {
            "type": "string",
            "enum": [
              "israeli_id",
              "passport",
              "association",
              "company"
            ],
            "description": "Identification document type"
          },
          "id_number": {
            "type": "string",
            "description": "Identification document number of the linked customer"
          },
          "id_country": {
            "type": "string",
            "description": "Country that issued the identification document (relevant for passports)"
          },
          "issue_date": {
            "type": "string",
            "format": "date",
            "description": "Issue date of the identification document"
          },
          "id_expiry_date": {
            "type": "string",
            "format": "date",
            "description": "Expiry date of the identification document"
          },
          "birth_date": {
            "type": "string",
            "format": "date",
            "description": "Date of birth"
          },
          "gender": {
            "type": "string",
            "enum": [
              "male",
              "female",
              "other"
            ],
            "description": "Gender"
          },
          "marital_status": {
            "type": "string",
            "enum": [
              "single",
              "married",
              "divorced",
              "widowed",
              "separated",
              "domestic_partnership",
              "other"
            ],
            "description": "Marital status"
          },
          "custom_marital_status": {
            "type": "string",
            "description": "Custom marital status (when marital_status=other)"
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "Email address"
          },
          "phone": {
            "type": "string",
            "description": "Phone number"
          },
          "street": {
            "type": "string",
            "description": "Street of residence"
          },
          "city": {
            "type": "string",
            "description": "City of residence"
          },
          "has_children": {
            "type": "boolean",
            "description": "Whether the borrower has children"
          },
          "children_under_18": {
            "type": "integer",
            "description": "Number of children under 18"
          },
          "children_birth_dates": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "date"
            },
            "description": "Children's dates of birth"
          },
          "has_foreign_citizenship": {
            "type": "boolean",
            "description": "Whether the borrower holds foreign citizenship"
          },
          "foreign_citizenship": {
            "type": "string",
            "description": "Country of the foreign citizenship"
          },
          "is_politically_exposed": {
            "type": "boolean",
            "description": "Whether the borrower is a politically exposed person (PEP)"
          },
          "relationship_type": {
            "type": "string",
            "enum": [
              "main",
              "spouse",
              "business_partner",
              "siblings",
              "other"
            ],
            "description": "The borrower's relationship to the file. The borrower with order_index=0 must be main"
          },
          "custom_relationship": {
            "type": "string",
            "description": "Custom relationship type (when relationship_type=other)"
          },
          "borrower_type": {
            "type": "string",
            "enum": [
              "regular",
              "paying_guarantor",
              "supporting_guarantor",
              "non_mortgaging_borrower"
            ],
            "description": "Borrower type"
          },
          "preferred_contact_methods": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "email",
                "sms",
                "whatsapp",
                "voice",
                "no_sms"
              ]
            },
            "description": "Preferred contact methods"
          },
          "order_index": {
            "type": "integer",
            "description": "The borrower's position in the file (0 = primary borrower)"
          }
        }
      },
      "BorrowerBase": {
        "type": "object",
        "description": "A borrower's link record to a file, without customer details",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Borrower ID"
          },
          "organization_id": {
            "type": "string",
            "format": "uuid"
          },
          "mortgage_file_id": {
            "type": "string",
            "format": "uuid"
          },
          "customer_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true,
            "description": "Linked customer ID"
          },
          "order_index": {
            "type": "integer"
          },
          "relationship_type": {
            "type": "string",
            "enum": [
              "main",
              "spouse",
              "business_partner",
              "siblings",
              "other"
            ],
            "nullable": true
          },
          "borrower_type": {
            "type": "string",
            "enum": [
              "regular",
              "paying_guarantor",
              "supporting_guarantor",
              "non_mortgaging_borrower"
            ],
            "nullable": true
          },
          "custom_relationship": {
            "type": "string",
            "nullable": true
          },
          "preferred_contact_methods": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          },
          "spouse_of_borrower_id": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "UpdateCustomer": {
        "type": "object",
        "description": "Partial update of a customer: only the fields sent are updated. Fields not listed here are ignored.",
        "properties": {
          "first_name": {
            "type": "string",
            "description": "First name"
          },
          "last_name": {
            "type": "string",
            "description": "Last name"
          },
          "entity_name": {
            "type": "string",
            "description": "Name of the company or nonprofit association (when id_type is company or association)"
          },
          "id_type": {
            "type": "string",
            "enum": [
              "israeli_id",
              "passport",
              "association",
              "company"
            ],
            "description": "Identification document type"
          },
          "id_number": {
            "type": "string",
            "description": "Identification document number. Unique within the organization: a number that already belongs to another customer is rejected by the database (409, code 23505)"
          },
          "id_country": {
            "type": "string",
            "description": "Country that issued the identification document (relevant for passports)"
          },
          "issue_date": {
            "type": "string",
            "format": "date",
            "description": "Issue date of the identification document"
          },
          "id_expiry_date": {
            "type": "string",
            "format": "date",
            "description": "Expiry date of the identification document"
          },
          "phone": {
            "type": "string",
            "description": "Phone number"
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "Email address"
          },
          "birth_date": {
            "type": "string",
            "format": "date",
            "description": "Date of birth"
          },
          "gender": {
            "type": "string",
            "enum": [
              "male",
              "female",
              "other"
            ],
            "description": "Gender"
          },
          "marital_status": {
            "type": "string",
            "enum": [
              "single",
              "married",
              "divorced",
              "widowed",
              "separated",
              "domestic_partnership",
              "other"
            ],
            "description": "Marital status"
          },
          "custom_marital_status": {
            "type": "string",
            "description": "Custom marital status (when marital_status=other)"
          },
          "street": {
            "type": "string",
            "description": "Street"
          },
          "city": {
            "type": "string",
            "description": "City"
          },
          "has_children": {
            "type": "boolean",
            "description": "Whether the customer has children"
          },
          "children_under_18": {
            "type": "integer",
            "description": "Number of children under 18"
          },
          "children_birth_dates": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "date"
            },
            "description": "Children's dates of birth"
          },
          "has_foreign_citizenship": {
            "type": "boolean",
            "description": "Whether the customer holds foreign citizenship"
          },
          "foreign_citizenship": {
            "type": "string",
            "description": "Country of the foreign citizenship"
          },
          "is_politically_exposed": {
            "type": "boolean",
            "description": "Whether the customer is a politically exposed person (PEP)"
          }
        }
      },
      "DeleteResult": {
        "type": "object",
        "description": "Deletion result",
        "properties": {
          "success": {
            "type": "boolean"
          },
          "message": {
            "type": "string",
            "description": "Confirmation message (in English)"
          }
        },
        "required": [
          "success",
          "message"
        ]
      }
    },
    "parameters": {
      "Limit": {
        "name": "limit",
        "in": "query",
        "required": false,
        "description": "Maximum number of results per page. Defaults to 50, maximum 500 (higher values are capped at 500). An invalid value (non-numeric, zero, or negative) is silently replaced with the default.",
        "schema": {
          "type": "integer",
          "default": 50,
          "minimum": 1,
          "maximum": 500
        }
      },
      "Offset": {
        "name": "offset",
        "in": "query",
        "required": false,
        "description": "Number of results to skip (for pagination). Defaults to 0, maximum 1,000,000. An invalid value is replaced with 0.",
        "schema": {
          "type": "integer",
          "default": 0,
          "minimum": 0,
          "maximum": 1000000
        }
      },
      "MortgageFileId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "Mortgage file ID",
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid request: the request body is not valid JSON or is not an object, a required field is missing or empty, a value is invalid, or an update includes no updatable fields (\"No updatable fields provided\"). The specific cases are listed in each operation's description. Database validation errors are also returned as 400 with a code field: 22P02 (a value in an invalid format, such as an unknown enum value or a malformed UUID), 23514 (a value that is not allowed, such as a status that is not defined in the organization) or 23503 (a reference to a record that does not exist).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": "Missing required fields",
              "details": "Missing required fields: phone",
              "status": 400,
              "validation": {
                "phone": "Required field"
              }
            }
          }
        }
      },
      "Unauthorized": {
        "description": "The API key is missing or invalid. The reason field indicates why: missing_api_key (no x-api-key header was sent), malformed_api_key (the key contains whitespace), invalid_api_key (the key does not exist, has been revoked, or has expired), auth_service_error (an error in the authentication service; you can retry).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": "Unauthorized",
              "status": 401,
              "reason": "invalid_api_key"
            }
          }
        }
      },
      "Forbidden": {
        "description": "The key does not have permission for this action on the resource (resource:action), for example write on leads. See the ApiKeyAuth security scheme.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": "Forbidden",
              "details": "API key lacks permission for write on leads",
              "status": 403
            }
          }
        }
      },
      "NotFound": {
        "description": "The record was not found in the key's organization, or it has been deleted. For paths under /mortgage-files/{id}/..., 404 is also returned when the mortgage file itself is not found.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": "Mortgage file not found",
              "details": "The specified mortgage file does not exist or you do not have access to it",
              "status": 404
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "Rate limit exceeded: 60 requests per API key in a fixed 60-second window. The window opens with the first request and resets 60 seconds later, and every request with a valid key counts, including rejected requests. retry_after indicates when the window resets.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": "Too Many Requests",
              "details": "Rate limit exceeded (61 requests in window)",
              "status": 429,
              "retry_after": "2026-10-14T08:16:00.000000+00:00"
            }
          }
        }
      },
      "InternalError": {
        "description": "Server or database error. When it is safe to expose, the code field contains the PostgREST/Postgres error code, for example 23502 (a missing value in a required field). Errors caused by invalid input (22P02, 23503, 23514) are returned as 400, and a duplicate value (23505) as 409.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "error": "Failed to update lead",
              "status": 500,
              "code": "22P02"
            }
          }
        }
      }
    }
  },
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "tags": [
    {
      "name": "Leads",
      "description": "Inquiries from prospective customers: creation, updates, status changes, and permanent deletion"
    },
    {
      "name": "Mortgage files",
      "description": "Mortgage files: creation (including borrowers, incomes, and obligations), updates, status changes, and deletion"
    },
    {
      "name": "Borrowers",
      "description": "Borrowers on a mortgage file. Each borrower is linked to a customer record"
    },
    {
      "name": "Customers",
      "description": "The organization's customers: the people and entities who act as borrowers on files"
    },
    {
      "name": "Contacts",
      "description": "The organization's professional contacts: bankers, appraisers, lawyers, and more"
    },
    {
      "name": "Lists",
      "description": "Fixed system value lists (read-only): employment types, mortgage types, document statuses, and more"
    },
    {
      "name": "Timeline",
      "description": "Timeline events of a mortgage file (read-only)"
    },
    {
      "name": "Tasks",
      "description": "Tasks, linked to a file, lead, or customer, or standalone"
    },
    {
      "name": "Notes",
      "description": "Free-text notes on a mortgage file"
    },
    {
      "name": "File contacts",
      "description": "Linking the organization's contacts to a mortgage file"
    },
    {
      "name": "Watchers",
      "description": "Organization users who watch a mortgage file"
    },
    {
      "name": "Documents",
      "description": "The customer's documents in the file and the file's document requirements (read-only)"
    },
    {
      "name": "Signatures",
      "description": "Borrower signatures on the file's documents (read-only)"
    },
    {
      "name": "Generated documents",
      "description": "Documents generated from templates for the file (read-only)"
    },
    {
      "name": "Document statuses",
      "description": "Tracking the documents requested from the file's borrowers and updating their status"
    },
    {
      "name": "Reminders",
      "description": "Scheduled reminders on a mortgage file"
    },
    {
      "name": "Charges",
      "description": "Charges (payment requests) on a file, including links to milestones"
    },
    {
      "name": "Payments",
      "description": "Payments received on a file"
    },
    {
      "name": "File analysis",
      "description": "Saved analyses on a file (free-form JSON)"
    },
    {
      "name": "Calculator mixes",
      "description": "Mortgage mixes saved to the file from the calculator"
    },
    {
      "name": "Custom fields",
      "description": "Values of the custom fields the organization has defined for mortgage files"
    },
    {
      "name": "Milestones",
      "description": "The file's milestones: combined view, custom milestones, progress, and checklist items"
    }
  ],
  "paths": {
    "/api-service/leads": {
      "get": {
        "tags": [
          "Leads"
        ],
        "summary": "List leads",
        "description": "Returns the organization's leads (excluding deleted leads), newest first, with pagination.",
        "operationId": "getLeads",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "new",
                "contacted",
                "qualified",
                "converted",
                "lost",
                "custom"
              ]
            },
            "description": "Filter by status. Leads with a custom status are stored with status=custom"
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Partial, case-insensitive search across first name, last name, phone, and email. The characters , ( ) % _ \\ \" ' are stripped from the search term before searching."
          }
        ],
        "responses": {
          "200": {
            "description": "List of leads",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Lead"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Total number of records matching the filter (not just those on the current page)"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "tags": [
          "Leads"
        ],
        "summary": "Create a lead",
        "description": "Creates a new lead in the organization.\n\n- Required: first_name, last_name, and phone (non-empty values). A missing field returns 400, and the missing fields are listed in validation.\n- Defaults: status=new, source=api, has_property=false.\n- status - a system status or one of the organization's custom statuses (see GET /leads/statuses); any other value returns 400.\n- An assigned_to value that is not the ID of an active user in the organization is ignored, and the lead is created unassigned.",
        "operationId": "createLead",
        "requestBody": {
          "description": "Details of the new lead",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateLead"
              },
              "example": {
                "first_name": "Dana",
                "last_name": "Levi",
                "phone": "050-0000000",
                "email": "dana.levi@example.com",
                "source": "website",
                "mortgage_purpose": "Second-hand apartment purchase",
                "required_amount": 1200000,
                "total_income": 28000,
                "has_property": false,
                "notes": "Prefers a call after 17:00"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The lead was created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Lead"
                },
                "example": {
                  "id": "6f1c2a9e-3b4d-4e5f-8a7b-1c2d3e4f5a6b",
                  "organization_id": "0b8e1f2a-7c3d-4a5b-9e6f-2a3b4c5d6e7f",
                  "first_name": "Dana",
                  "last_name": "Levi",
                  "email": "dana.levi@example.com",
                  "phone": "050-0000000",
                  "source": "website",
                  "status": "new",
                  "status_custom": null,
                  "notes": "Prefers a call after 17:00",
                  "mortgage_purpose": "Second-hand apartment purchase",
                  "required_amount": 1200000,
                  "total_income": 28000,
                  "has_property": false,
                  "assigned_to": null,
                  "created_at": "2026-10-14T08:15:22.481234+00:00",
                  "updated_at": "2026-10-14T08:15:22.481234+00:00"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/leads/{id}": {
      "get": {
        "tags": [
          "Leads"
        ],
        "summary": "Get a lead",
        "description": "Returns a lead by ID.",
        "operationId": "getLeadById",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Lead ID"
          }
        ],
        "responses": {
          "200": {
            "description": "Lead details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Lead"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "put": {
        "tags": [
          "Leads"
        ],
        "summary": "Update a lead",
        "description": "Partially updates a lead: only the fields sent are updated (PUT and PATCH are identical). If no updatable field is sent, returns 400. assigned_to=null (or an empty string) removes the assignment; an ID that does not belong to an active user in the organization is ignored. To change the status and record the change in the lead's status history, use PATCH /leads/{id}/status.",
        "operationId": "updateLead",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Lead ID"
          }
        ],
        "requestBody": {
          "description": "The fields to update",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateLead"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated lead",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Lead"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "patch": {
        "tags": [
          "Leads"
        ],
        "summary": "Partially update a lead",
        "description": "Partially updates a lead: only the fields sent are updated (PUT and PATCH are identical). If no updatable field is sent, returns 400. assigned_to=null (or an empty string) removes the assignment; an ID that does not belong to an active user in the organization is ignored. To change the status and record the change in the lead's status history, use PATCH /leads/{id}/status.",
        "operationId": "patchLead",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Lead ID"
          }
        ],
        "requestBody": {
          "description": "The fields to update",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateLead"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated lead",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Lead"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "delete": {
        "tags": [
          "Leads"
        ],
        "summary": "Permanently delete a lead",
        "description": "Deletes the lead **permanently** (hard delete). This action cannot be undone: leads have no recycle bin. Records that depend solely on the lead are deleted along with it, while records that can exist without it (for example, a mortgage file created from the lead) are kept and unlinked from it.",
        "operationId": "deleteLead",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Lead ID"
          }
        ],
        "responses": {
          "200": {
            "description": "The lead was permanently deleted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteResult"
                },
                "example": {
                  "success": true,
                  "message": "Lead permanently deleted"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/leads/{id}/status": {
      "patch": {
        "tags": [
          "Leads"
        ],
        "summary": "Update a lead's status",
        "description": "Changes the lead's status, updates status_changed_at, and records the change in the lead's status history. status can be a system status (new, contacted, qualified, converted, lost) or one of the organization's custom statuses (the value field in GET /leads/statuses); a custom status is stored as status=custom with its key in status_custom. Any other value returns 400. notes (optional) is saved in the status history only. A missing status returns 400.",
        "operationId": "updateLeadStatus",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Lead ID"
          }
        ],
        "requestBody": {
          "description": "The new status",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "description": "The new status: a system status or one of the organization's custom statuses (see GET /leads/statuses)"
                  },
                  "notes": {
                    "type": "string",
                    "description": "A note on the status change, saved in the status history"
                  }
                },
                "required": [
                  "status"
                ]
              },
              "example": {
                "status": "contacted",
                "notes": "First call completed, meeting scheduled"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The lead after the status update",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Lead"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/leads/statuses": {
      "get": {
        "tags": [
          "Leads"
        ],
        "summary": "List lead statuses",
        "description": "Returns the organization's lead status configuration. If the organization has defined its own statuses, source=custom and the items are the organization's stored definitions (their structure may differ from the default). Otherwise, source=default and the items are the system statuses.\n\nUse the value field of an item as status in POST /leads, PUT/PATCH /leads/{id} and PATCH /leads/{id}/status.",
        "operationId": "getLeadStatuses",
        "responses": {
          "200": {
            "description": "Lead statuses",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/LeadStatus"
                      },
                      "description": "List of statuses"
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items in the data array"
                    },
                    "source": {
                      "type": "string",
                      "enum": [
                        "default",
                        "custom"
                      ],
                      "description": "Source of the list: the organization's configuration (custom) or the default (default)"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "value": "new",
                      "label": "חדש",
                      "color": {
                        "bg": "#3498db",
                        "text": "#ffffff"
                      },
                      "is_default": true
                    },
                    {
                      "value": "contacted",
                      "label": "נוצר קשר",
                      "color": {
                        "bg": "#f39c12",
                        "text": "#ffffff"
                      },
                      "is_default": false
                    },
                    {
                      "value": "qualified",
                      "label": "מתאים",
                      "color": {
                        "bg": "#2ecc71",
                        "text": "#ffffff"
                      },
                      "is_default": false
                    },
                    {
                      "value": "converted",
                      "label": "הומר ללקוח",
                      "color": {
                        "bg": "#1abc9c",
                        "text": "#ffffff"
                      },
                      "is_default": false
                    },
                    {
                      "value": "lost",
                      "label": "אבוד",
                      "color": {
                        "bg": "#e74c3c",
                        "text": "#ffffff"
                      },
                      "is_default": false
                    }
                  ],
                  "count": 5,
                  "source": "default"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files": {
      "get": {
        "tags": [
          "Mortgage files"
        ],
        "summary": "List mortgage files",
        "description": "Returns the organization's mortgage files (excluding deleted files), newest first, with pagination. Each file includes the borrowers array, which holds the file's active borrowers.",
        "operationId": "getMortgageFiles",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter by status key (see GET /mortgage-files/statuses)"
          },
          {
            "name": "customer_id",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter to a customer's files (the file's primary customer)"
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Partial, case-insensitive search across the file number and title. The characters , ( ) % _ \\ \" ' are stripped from the search term before searching."
          }
        ],
        "responses": {
          "200": {
            "description": "List of mortgage files",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/MortgageFileDetails"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Total number of records matching the filter (not just those on the current page)"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "tags": [
          "Mortgage files"
        ],
        "summary": "Create a mortgage file",
        "description": "Creates a new mortgage file and, optionally, in the same request, its borrowers, incomes, bank accounts, and obligations. No fields are required.\n\n- **status** - If omitted, the organization's default status is used (set in the app's mortgage status settings), or `setup` if none is set. A value you send must be a valid status in the organization: one of the system statuses (setup, pending_approval, pending_appraisal, reviewing, signing, completed, paused, cancelled, active) or a custom status defined by the organization (see GET /mortgage-files/statuses). Otherwise the API returns 400 (code 23514).\n- **customer_id / lead_id / source_lead_id** - Must be IDs of active records in the organization; otherwise the API returns 400.\n- **file_number** - The API does not assign a file number automatically.\n- **assigned_to** - An ID that does not belong to an active user in the organization is ignored, and the mortgage file is created unassigned.\n- **borrowers** - Each borrower is created as in POST /mortgage-files/{id}/borrowers (an existing customer is matched by id_number, or a new customer is created). The first borrower defaults to relationship_type=main, and subsequent borrowers default to spouse.\n- **incomes / bank_accounts / obligations** - Saved as sent.\n\nA failure to create a borrower or to save incomes, bank accounts, or obligations does not roll back the creation of the mortgage file: the response is 201, and the failures are listed in the child_errors array.",
        "operationId": "createMortgageFile",
        "requestBody": {
          "description": "Details of the new mortgage file",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateMortgageFile"
              },
              "example": {
                "file_number": "2026-0042",
                "title": "Apartment purchase - Cohen family",
                "status": "setup",
                "customer_id": "5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d",
                "purposes": [
                  {
                    "type": "second_hand",
                    "amount": 1200000
                  }
                ],
                "loan_amount": 1200000,
                "property_type": "apartment",
                "property_value": 2000000,
                "property_address": "10 Herzl St., Ramat Gan",
                "equity": 800000,
                "borrowers": [
                  {
                    "first_name": "Yossi",
                    "last_name": "Cohen",
                    "id_number": "000000018",
                    "phone": "052-0000000",
                    "email": "yossi.cohen@example.com",
                    "relationship_type": "main"
                  },
                  {
                    "first_name": "Ronit",
                    "last_name": "Cohen",
                    "id_number": "000000026",
                    "phone": "054-0000000",
                    "relationship_type": "spouse"
                  }
                ],
                "incomes": {
                  "borrowers": [
                    {
                      "borrowerName": "Yossi Cohen",
                      "employments": [
                        {
                          "type": "salaried",
                          "data": {
                            "employers": [
                              {
                                "company_name": "Example Company Ltd.",
                                "position": "Engineer",
                                "start_date": "2019-01-01",
                                "is_current": true
                              }
                            ]
                          }
                        }
                      ]
                    }
                  ]
                },
                "bank_accounts": [
                  {
                    "bankName": "12",
                    "bankDisplayName": "Example Bank",
                    "branchName": "600",
                    "branchDisplayName": "Central Branch",
                    "accountNumber": "123456",
                    "isJoint": true
                  }
                ],
                "obligations": [
                  {
                    "type": "bank_loan",
                    "monthlyPayment": 1500,
                    "remainingAmount": 30000,
                    "endDate": "2027-12-31"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Mortgage file created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MortgageFileCreateResult"
                },
                "example": {
                  "id": "c4d5e6f7-8a9b-4c0d-9e1f-2a3b4c5d6e7f",
                  "organization_id": "0b8e1f2a-7c3d-4a5b-9e6f-2a3b4c5d6e7f",
                  "file_number": "2026-0042",
                  "title": "Apartment purchase - Cohen family",
                  "status": "setup",
                  "customer_id": "5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d",
                  "assigned_to": null,
                  "purposes": [
                    {
                      "type": "second_hand",
                      "amount": 1200000
                    }
                  ],
                  "loan_amount": 1200000,
                  "property_type": "apartment",
                  "property_value": 2000000,
                  "property_address": "10 Herzl St., Ramat Gan",
                  "equity": 800000,
                  "created_at": "2026-10-14T08:15:22.481234+00:00",
                  "updated_at": "2026-10-14T08:15:22.481234+00:00",
                  "borrowers": [
                    {
                      "id": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
                      "organization_id": "0b8e1f2a-7c3d-4a5b-9e6f-2a3b4c5d6e7f",
                      "mortgage_file_id": "c4d5e6f7-8a9b-4c0d-9e1f-2a3b4c5d6e7f",
                      "customer_id": "5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d",
                      "order_index": 0,
                      "relationship_type": "main",
                      "borrower_type": "regular",
                      "custom_relationship": null,
                      "preferred_contact_methods": []
                    },
                    {
                      "id": "3c4d5e6f-7a8b-4c9d-8e0f-2a3b4c5d6e7f",
                      "organization_id": "0b8e1f2a-7c3d-4a5b-9e6f-2a3b4c5d6e7f",
                      "mortgage_file_id": "c4d5e6f7-8a9b-4c0d-9e1f-2a3b4c5d6e7f",
                      "customer_id": "7c8d9e0f-1a2b-4c3d-9e4f-5a6b7c8d9e0f",
                      "order_index": 1,
                      "relationship_type": "spouse",
                      "borrower_type": "regular",
                      "custom_relationship": null,
                      "preferred_contact_methods": []
                    }
                  ],
                  "incomes": {
                    "borrowers": [
                      {
                        "borrowerName": "Yossi Cohen",
                        "employments": [
                          {
                            "type": "salaried",
                            "data": {
                              "employers": [
                                {
                                  "company_name": "Example Company Ltd.",
                                  "position": "Engineer",
                                  "start_date": "2019-01-01",
                                  "is_current": true
                                }
                              ]
                            }
                          }
                        ]
                      }
                    ]
                  },
                  "bank_accounts": [
                    {
                      "bankName": "12",
                      "bankDisplayName": "Example Bank",
                      "branchName": "600",
                      "branchDisplayName": "Central Branch",
                      "accountNumber": "123456",
                      "isJoint": true
                    }
                  ],
                  "obligations": [
                    {
                      "type": "bank_loan",
                      "monthlyPayment": 1500,
                      "remainingAmount": 30000,
                      "endDate": "2027-12-31"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}": {
      "get": {
        "tags": [
          "Mortgage files"
        ],
        "summary": "Get a mortgage file",
        "description": "Returns the mortgage file together with a borrowers array containing the file's active borrowers.",
        "operationId": "getMortgageFileById",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          }
        ],
        "responses": {
          "200": {
            "description": "Mortgage file details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MortgageFileDetails"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "put": {
        "tags": [
          "Mortgage files"
        ],
        "summary": "Update a mortgage file",
        "description": "Partial update: only the fields you send are updated (PUT and PATCH behave identically). If no updatable field is sent, the API returns 400.\n\nYou can also update incomes, bank_accounts, and obligations. The value you send replaces the stored value (sending only bank_accounts leaves the stored obligations unchanged, and vice versa). Borrowers are not updated here; use /mortgage-files/{id}/borrowers instead. To change the status, we recommend using PATCH /mortgage-files/{id}/status.\n\nThe response does not include borrowers. incomes, bank_accounts, and obligations are returned only if they were sent in the request (otherwise null). Failures to save them are reported in child_errors.\n\ncustomer_id, lead_id and source_lead_id must be IDs of active records in the organization (otherwise 400).",
        "operationId": "updateMortgageFile",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          }
        ],
        "requestBody": {
          "description": "Fields to update",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateMortgageFile"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated mortgage file",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MortgageFileUpdateResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "patch": {
        "tags": [
          "Mortgage files"
        ],
        "summary": "Partially update a mortgage file",
        "description": "Partial update: only the fields you send are updated (PUT and PATCH behave identically). If no updatable field is sent, the API returns 400.\n\nYou can also update incomes, bank_accounts, and obligations. The value you send replaces the stored value (sending only bank_accounts leaves the stored obligations unchanged, and vice versa). Borrowers are not updated here; use /mortgage-files/{id}/borrowers instead. To change the status, we recommend using PATCH /mortgage-files/{id}/status.\n\nThe response does not include borrowers. incomes, bank_accounts, and obligations are returned only if they were sent in the request (otherwise null). Failures to save them are reported in child_errors.\n\ncustomer_id, lead_id and source_lead_id must be IDs of active records in the organization (otherwise 400).",
        "operationId": "patchMortgageFile",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          }
        ],
        "requestBody": {
          "description": "Fields to update",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateMortgageFile"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated mortgage file",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MortgageFileUpdateResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "delete": {
        "tags": [
          "Mortgage files"
        ],
        "summary": "Delete a mortgage file",
        "description": "Soft delete: the mortgage file is marked as deleted and is no longer returned by the API.",
        "operationId": "deleteMortgageFile",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          }
        ],
        "responses": {
          "200": {
            "description": "Mortgage file deleted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteResult"
                },
                "example": {
                  "success": true,
                  "message": "Mortgage file deleted successfully"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/status": {
      "patch": {
        "tags": [
          "Mortgage files"
        ],
        "summary": "Update a mortgage file's status",
        "description": "Changes the mortgage file's status and updates status_changed_at. The status must be valid in the organization: a system status or a custom status (see GET /mortgage-files/statuses); otherwise the API returns 400 (code 23514). A missing status returns 400. notes (optional) is saved as the file's status_comment. The change is recorded in the file's timeline (event type status_updated). The response is the mortgage file record, without borrowers.",
        "operationId": "updateMortgageFileStatus",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          }
        ],
        "requestBody": {
          "description": "The new status",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateMortgageStatus"
              },
              "example": {
                "status": "signing",
                "notes": "Approval in principle received"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The mortgage file after the status update",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MortgageFile"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/statuses": {
      "get": {
        "tags": [
          "Mortgage files"
        ],
        "summary": "List mortgage file statuses",
        "description": "Returns the organization's mortgage file status configuration. If the organization has its own status configuration, source=custom and the items are the organization's definitions, excluding hidden statuses (items may include additional fields, such as each status's milestones). Otherwise, source=default and a fixed default list is returned.",
        "operationId": "getMortgageFileStatuses",
        "responses": {
          "200": {
            "description": "Mortgage file statuses",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/MortgageStatus"
                      },
                      "description": "List of statuses"
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items in the data array"
                    },
                    "source": {
                      "type": "string",
                      "enum": [
                        "default",
                        "custom"
                      ],
                      "description": "Source of the list: the organization's configuration (custom) or the default list (default)"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/borrowers": {
      "get": {
        "tags": [
          "Borrowers"
        ],
        "summary": "List a mortgage file's borrowers",
        "description": "Returns the mortgage file's active borrowers in their order (order_index), without pagination.",
        "operationId": "getMortgageFileBorrowers",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          }
        ],
        "responses": {
          "200": {
            "description": "List of borrowers",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Borrower"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items in the data array"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "tags": [
          "Borrowers"
        ],
        "summary": "Add a borrower to a mortgage file",
        "description": "Adds a borrower to the mortgage file and links it to a customer record:\n- If **id_number** is sent, the API looks up an active customer in the organization with the same ID number, and the customer fields you send **update the existing customer**. If no such customer exists, a new customer is created (id_type defaults to israeli_id; creating a customer requires first_name and last_name, otherwise the API returns 500 with code 23502).\n- If id_number is not sent, the borrower is linked to the customer_id you send (if any), **and the customer fields in the request are not saved**. customer_id must belong to an active customer in the organization; otherwise the API returns 400 (Invalid customer_id).\n\nDefaults: order_index = the number of existing borrowers in the mortgage file; relationship_type = main for the first borrower and spouse for subsequent ones; borrower_type = regular. A borrower with order_index=0 must be main (otherwise 400, code 23514).",
        "operationId": "addBorrowerToMortgageFile",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          }
        ],
        "requestBody": {
          "description": "Borrower details",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateBorrower"
              },
              "example": {
                "first_name": "Ronit",
                "last_name": "Cohen",
                "id_number": "000000026",
                "phone": "054-0000000",
                "email": "ronit.cohen@example.com",
                "relationship_type": "spouse"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Borrower added (including the linked customer's details)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Borrower"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/borrowers/{borrowerId}": {
      "put": {
        "tags": [
          "Borrowers"
        ],
        "summary": "Update a borrower",
        "description": "Partial update (PUT and PATCH behave identically). Customer fields (name, identification, contact details, etc.) update the linked customer record, and the change applies to every mortgage file in which that customer is a borrower; for a borrower that is not linked to a customer, these fields are not saved. Association fields (relationship_type, custom_relationship, borrower_type, preferred_contact_methods, order_index) apply only to the borrower in this mortgage file. A request with no recognized fields returns the borrower unchanged.",
        "operationId": "updateMortgageFileBorrower",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "borrowerId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Borrower ID (the id from the mortgage file's list of borrowers)"
          }
        ],
        "requestBody": {
          "description": "Fields to update",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateBorrower"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated borrower",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Borrower"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "patch": {
        "tags": [
          "Borrowers"
        ],
        "summary": "Partially update a borrower",
        "description": "Partial update (PUT and PATCH behave identically). Customer fields (name, identification, contact details, etc.) update the linked customer record, and the change applies to every mortgage file in which that customer is a borrower; for a borrower that is not linked to a customer, these fields are not saved. Association fields (relationship_type, custom_relationship, borrower_type, preferred_contact_methods, order_index) apply only to the borrower in this mortgage file. A request with no recognized fields returns the borrower unchanged.",
        "operationId": "patchMortgageFileBorrower",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "borrowerId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Borrower ID (the id from the mortgage file's list of borrowers)"
          }
        ],
        "requestBody": {
          "description": "Fields to update",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateBorrower"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated borrower",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Borrower"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "delete": {
        "tags": [
          "Borrowers"
        ],
        "summary": "Remove a borrower from a mortgage file",
        "description": "Removes the borrower from the mortgage file (a soft delete of the association). The customer record itself is not deleted.",
        "operationId": "removeBorrowerFromMortgageFile",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "borrowerId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Borrower ID (the id from the mortgage file's list of borrowers)"
          }
        ],
        "responses": {
          "200": {
            "description": "Borrower removed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteResult"
                },
                "example": {
                  "success": true,
                  "message": "Borrower deleted successfully"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/customers": {
      "get": {
        "tags": [
          "Customers"
        ],
        "summary": "List customers",
        "description": "Returns the organization's customers (excluding deleted customers), newest first, with pagination. The list does not include mortgage_files; they are returned only when you retrieve a single customer.",
        "operationId": "getCustomers",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Partial, case-insensitive search across first name, last name, phone, email, and ID number. The characters , ( ) % _ \\ \" ' are removed from the search term before searching."
          }
        ],
        "responses": {
          "200": {
            "description": "List of customers",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Customer"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Total number of records matching the filter (not just those on the current page)"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "tags": [
          "Customers"
        ],
        "summary": "Create a customer",
        "description": "Creates a new customer in the organization.\n\n- Required: first_name and last_name. A missing field returns 400 with a validation object.\n- id_type defaults to israeli_id.\n- If id_number already belongs to an active customer in the organization, the API returns 409, and the existing customer's ID is returned in existing_customer_id.",
        "operationId": "createCustomer",
        "requestBody": {
          "description": "Details of the new customer",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCustomer"
              },
              "example": {
                "first_name": "Yossi",
                "last_name": "Cohen",
                "id_type": "israeli_id",
                "id_number": "000000018",
                "phone": "052-0000000",
                "email": "yossi.cohen@example.com",
                "birth_date": "1988-04-12",
                "gender": "male",
                "marital_status": "married",
                "street": "10 Herzl St.",
                "city": "Ramat Gan"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Customer created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Customer"
                },
                "example": {
                  "id": "5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d",
                  "organization_id": "0b8e1f2a-7c3d-4a5b-9e6f-2a3b4c5d6e7f",
                  "first_name": "Yossi",
                  "last_name": "Cohen",
                  "id_type": "israeli_id",
                  "id_number": "000000018",
                  "phone": "052-0000000",
                  "email": "yossi.cohen@example.com",
                  "birth_date": "1988-04-12",
                  "gender": "male",
                  "marital_status": "married",
                  "street": "10 Herzl St.",
                  "city": "Ramat Gan",
                  "created_at": "2026-10-14T08:15:22.481234+00:00",
                  "updated_at": "2026-10-14T08:15:22.481234+00:00"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "A customer with the same id_number already exists in the organization. The existing customer's ID is returned in existing_customer_id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Customer with this ID number already exists",
                  "details": "A customer with this ID number is already registered in your organization",
                  "status": 409,
                  "existing_customer_id": "5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/customers/{id}": {
      "get": {
        "tags": [
          "Customers"
        ],
        "summary": "Get a customer",
        "description": "Returns the customer together with mortgage_files: the active mortgage files in which the customer is the primary customer (customer_id), without borrowers.",
        "operationId": "getCustomerById",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Customer ID"
          }
        ],
        "responses": {
          "200": {
            "description": "Customer details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Customer"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "put": {
        "tags": [
          "Customers"
        ],
        "summary": "Update a customer",
        "description": "Partial update: only the fields you send are updated (PUT and PATCH behave identically). If no updatable field is sent, the API returns 400. Updates do not check id_number for duplicates at the API level; a number that already belongs to another customer is rejected by the database (409, code 23505).",
        "operationId": "updateCustomer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Customer ID"
          }
        ],
        "requestBody": {
          "description": "Fields to update",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCustomer"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated customer",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Customer"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "patch": {
        "tags": [
          "Customers"
        ],
        "summary": "Partially update a customer",
        "description": "Partial update: only the fields you send are updated (PUT and PATCH behave identically). If no updatable field is sent, the API returns 400. Updates do not check id_number for duplicates at the API level; a number that already belongs to another customer is rejected by the database (409, code 23505).",
        "operationId": "partialUpdateCustomer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Customer ID"
          }
        ],
        "requestBody": {
          "description": "Fields to update",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCustomer"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated customer",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Customer"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "delete": {
        "tags": [
          "Customers"
        ],
        "summary": "Delete a customer",
        "description": "Soft delete. A customer who is the primary customer of an active mortgage file cannot be deleted; the API returns 409 with related_files_count.",
        "operationId": "deleteCustomer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Customer ID"
          }
        ],
        "responses": {
          "200": {
            "description": "Customer deleted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteResult"
                },
                "example": {
                  "success": true,
                  "message": "Customer deleted successfully"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "The customer has active mortgage files. Their count is returned in related_files_count",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Cannot delete customer",
                  "details": "This customer has active mortgage files. You must delete the mortgage files first.",
                  "status": 409,
                  "related_files_count": 2
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/customers/{id}/mortgage-files": {
      "get": {
        "tags": [
          "Customers",
          "Mortgage files"
        ],
        "summary": "List a customer's mortgage files",
        "description": "Returns the active mortgage files in which the customer is the primary customer (customer_id), newest first. To filter and paginate, use GET /mortgage-files?customer_id={id}.",
        "operationId": "getCustomerMortgageFiles",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Customer ID"
          }
        ],
        "responses": {
          "200": {
            "description": "The customer's mortgage files",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/MortgageFile"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of mortgage files"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/lists": {
      "get": {
        "tags": [
          "Lists"
        ],
        "summary": "List available lists",
        "description": "Returns all available lists, with the path and number of items of each.",
        "operationId": "getAvailableLists",
        "responses": {
          "200": {
            "description": "Available lists",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "key": {
                            "type": "string",
                            "description": "List identifier"
                          },
                          "endpoint": {
                            "type": "string",
                            "description": "API path for retrieving the list"
                          },
                          "count": {
                            "type": "integer",
                            "description": "Number of items in the list"
                          }
                        }
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of available lists"
                    },
                    "description": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "data": [
                    {
                      "key": "employment-types",
                      "endpoint": "/api-service/lists/employment-types",
                      "count": 9
                    },
                    {
                      "key": "income-types",
                      "endpoint": "/api-service/lists/income-types",
                      "count": 5
                    },
                    {
                      "key": "obligation-types",
                      "endpoint": "/api-service/lists/obligation-types",
                      "count": 6
                    },
                    {
                      "key": "mortgage-types",
                      "endpoint": "/api-service/lists/mortgage-types",
                      "count": 20
                    },
                    {
                      "key": "registration-types",
                      "endpoint": "/api-service/lists/registration-types",
                      "count": 9
                    },
                    {
                      "key": "mishach-types",
                      "endpoint": "/api-service/lists/mishach-types",
                      "count": 3
                    },
                    {
                      "key": "upload-document-statuses",
                      "endpoint": "/api-service/lists/upload-document-statuses",
                      "count": 6
                    },
                    {
                      "key": "signature-document-statuses",
                      "endpoint": "/api-service/lists/signature-document-statuses",
                      "count": 4
                    },
                    {
                      "key": "additional-expense-types",
                      "endpoint": "/api-service/lists/additional-expense-types",
                      "count": 8
                    },
                    {
                      "key": "calendar-event-types",
                      "endpoint": "/api-service/lists/calendar-event-types",
                      "count": 10
                    }
                  ],
                  "count": 10,
                  "description": "רשימת כל סוגי הרשימות הזמינות"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/lists/employment-types": {
      "get": {
        "tags": [
          "Lists"
        ],
        "summary": "List employment types",
        "description": "Returns the employment types (salaried employee, self-employed, retiree, etc.). These are the keys for the employment type field in the incomes structure.",
        "operationId": "getEmploymentTypes",
        "responses": {
          "200": {
            "description": "Employment types",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListResponse"
                },
                "example": {
                  "data": [
                    {
                      "key": "salaried",
                      "label": "שכיר"
                    },
                    {
                      "key": "self_employed",
                      "label": "עצמאי"
                    },
                    {
                      "key": "scholarship",
                      "label": "מלגת לימודים"
                    },
                    {
                      "key": "child_benefit",
                      "label": "קצבת ילדים"
                    },
                    {
                      "key": "kollel",
                      "label": "אברך כולל"
                    },
                    {
                      "key": "pension",
                      "label": "פנסיה"
                    },
                    {
                      "key": "allowance",
                      "label": "קצבה"
                    },
                    {
                      "key": "other",
                      "label": "אחר"
                    },
                    {
                      "key": "unemployed",
                      "label": "לא עובד"
                    }
                  ],
                  "count": 9,
                  "list_type": "employment-types"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/lists/income-types": {
      "get": {
        "tags": [
          "Lists"
        ],
        "summary": "List additional income types",
        "description": "Returns the additional income types (rental, dividends, alimony, etc.).",
        "operationId": "getIncomeTypes",
        "responses": {
          "200": {
            "description": "Additional income types",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListResponse"
                },
                "example": {
                  "data": [
                    {
                      "key": "rental",
                      "label": "הכנסה מדירה/נכס"
                    },
                    {
                      "key": "dividend",
                      "label": "דיבידנד"
                    },
                    {
                      "key": "alimony",
                      "label": "מזונות"
                    },
                    {
                      "key": "child_disability",
                      "label": "קצבת ילד נכה"
                    },
                    {
                      "key": "other",
                      "label": "אחר"
                    }
                  ],
                  "count": 5,
                  "list_type": "income-types"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/lists/obligation-types": {
      "get": {
        "tags": [
          "Lists"
        ],
        "summary": "List obligation types",
        "description": "Returns the obligation types (loans, mortgage, alimony, etc.). These are the keys for the type field in obligations.",
        "operationId": "getObligationTypes",
        "responses": {
          "200": {
            "description": "Obligation types",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListResponse"
                },
                "example": {
                  "data": [
                    {
                      "key": "bank_loan",
                      "label": "הלוואה בנקאית"
                    },
                    {
                      "key": "non_bank_loan",
                      "label": "הלוואה חוץ בנקאית"
                    },
                    {
                      "key": "mortgage",
                      "label": "משכנתא"
                    },
                    {
                      "key": "alimony",
                      "label": "מזונות"
                    },
                    {
                      "key": "rent",
                      "label": "שכירות"
                    },
                    {
                      "key": "other",
                      "label": "אחר"
                    }
                  ],
                  "count": 6,
                  "list_type": "obligation-types"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/lists/mortgage-types": {
      "get": {
        "tags": [
          "Lists"
        ],
        "summary": "List mortgage types",
        "description": "Returns the mortgage types (purchase from a contractor, second-hand purchase, refinancing, etc.). These are the keys for the purposes[].type field of a mortgage file. The list also includes legacy combined types retained for backward compatibility.",
        "operationId": "getMortgageTypes",
        "responses": {
          "200": {
            "description": "Mortgage types",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListResponse"
                },
                "example": {
                  "data": [
                    {
                      "key": "new_contractor",
                      "label": "רכישה מקבלן"
                    },
                    {
                      "key": "subsidized_price",
                      "label": "רכישה במחיר למשתכן"
                    },
                    {
                      "key": "second_hand",
                      "label": "רכישה יד שניה"
                    },
                    {
                      "key": "amidar",
                      "label": "רכישה מעמידר"
                    },
                    {
                      "key": "divorce",
                      "label": "רכישה אגב גירושין"
                    },
                    {
                      "key": "land_purchase_rami",
                      "label": "רכישת מגרש מרמ\"י"
                    },
                    {
                      "key": "refinance",
                      "label": "מיחזור משכנתא"
                    },
                    {
                      "key": "expansion",
                      "label": "הרחבה / בניה עצמית"
                    },
                    {
                      "key": "first_expansion",
                      "label": "הרחבה (משכנתא ראשונה)"
                    },
                    {
                      "key": "renovations",
                      "label": "שיפוצים"
                    },
                    {
                      "key": "any_purpose",
                      "label": "כל מטרה"
                    },
                    {
                      "key": "dowry",
                      "label": "נדוניה"
                    },
                    {
                      "key": "bridge_loan",
                      "label": "הלוואת גישור"
                    },
                    {
                      "key": "business_loan",
                      "label": "הלוואה עסקית"
                    },
                    {
                      "key": "overdraft_loan",
                      "label": "הלוואת עו\"ש"
                    },
                    {
                      "key": "self_construction",
                      "label": "בניה עצמית"
                    },
                    {
                      "key": "refinance_expansion",
                      "label": "מיחזור + הרחבה"
                    },
                    {
                      "key": "refinance_renovations",
                      "label": "מיחזור + שיפוצים"
                    },
                    {
                      "key": "refinance_any_purpose",
                      "label": "מיחזור + כל מטרה"
                    },
                    {
                      "key": "refinance_dowry",
                      "label": "מיחזור + נדוניה"
                    }
                  ],
                  "count": 20,
                  "list_type": "mortgage-types"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/lists/registration-types": {
      "get": {
        "tags": [
          "Lists"
        ],
        "summary": "List property registration types",
        "description": "Returns the property registration types (Land Registry (Tabu), Israel Land Authority (RMI), housing company, etc.).",
        "operationId": "getRegistrationTypes",
        "responses": {
          "200": {
            "description": "Registration types",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListResponse"
                },
                "example": {
                  "data": [
                    {
                      "key": "tabu",
                      "label": "טאבו"
                    },
                    {
                      "key": "tabu_mortgage_company",
                      "label": "טאבו + חברה משכנת"
                    },
                    {
                      "key": "tabu_no_ownership",
                      "label": "טאבו ללא בעלות"
                    },
                    {
                      "key": "tabu_musha",
                      "label": "טאבו במושע"
                    },
                    {
                      "key": "rami",
                      "label": "רמי"
                    },
                    {
                      "key": "rami_mortgage_company",
                      "label": "רמי + חברה משכנת"
                    },
                    {
                      "key": "zionist_organization",
                      "label": "ההסתדרות הציונית"
                    },
                    {
                      "key": "jordanian_tabu",
                      "label": "טאבו ירדני"
                    },
                    {
                      "key": "other",
                      "label": "אחר"
                    }
                  ],
                  "count": 9,
                  "list_type": "registration-types"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/lists/mishach-types": {
      "get": {
        "tags": [
          "Lists"
        ],
        "summary": "List real estate tax (Mas Shevach) declaration types",
        "description": "Returns the real estate tax (Mas Shevach) declaration types: single apartment, replacement apartment and investment apartment.",
        "operationId": "getMishachTypes",
        "responses": {
          "200": {
            "description": "Real estate tax (Mas Shevach) declaration types",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListResponse"
                },
                "example": {
                  "data": [
                    {
                      "key": "single_apartment",
                      "label": "דירה יחידה"
                    },
                    {
                      "key": "replacement_apartment",
                      "label": "דירה חליפית"
                    },
                    {
                      "key": "investment_apartment",
                      "label": "דירה להשקעה"
                    }
                  ],
                  "count": 3,
                  "list_type": "mishach-types"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/lists/upload-document-statuses": {
      "get": {
        "tags": [
          "Lists"
        ],
        "summary": "List document upload statuses",
        "description": "Returns the statuses of a document requested for upload, with display colors (HEX).",
        "operationId": "getUploadDocumentStatuses",
        "responses": {
          "200": {
            "description": "Document upload statuses",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StatusListResponse"
                },
                "example": {
                  "data": [
                    {
                      "key": "pending",
                      "label": "ממתין להעלאה",
                      "bgColor": "#fef9c3",
                      "textColor": "#854d0e"
                    },
                    {
                      "key": "uploading",
                      "label": "בהעלאה",
                      "bgColor": "#dbeafe",
                      "textColor": "#1d4ed8"
                    },
                    {
                      "key": "under_review",
                      "label": "בבדיקה",
                      "bgColor": "#f3e8ff",
                      "textColor": "#7e22ce"
                    },
                    {
                      "key": "completed",
                      "label": "הושלם",
                      "bgColor": "#dcfce7",
                      "textColor": "#166534"
                    },
                    {
                      "key": "rejected",
                      "label": "נדחה",
                      "bgColor": "#fee2e2",
                      "textColor": "#dc2626"
                    },
                    {
                      "key": "expired",
                      "label": "פג תוקף",
                      "bgColor": "#f3f4f6",
                      "textColor": "#4b5563"
                    }
                  ],
                  "count": 6,
                  "list_type": "upload-document-statuses"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/lists/signature-document-statuses": {
      "get": {
        "tags": [
          "Lists"
        ],
        "summary": "List document signature statuses",
        "description": "Returns the statuses of a document sent for signature, with display colors (HEX).",
        "operationId": "getSignatureDocumentStatuses",
        "responses": {
          "200": {
            "description": "Document signature statuses",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StatusListResponse"
                },
                "example": {
                  "data": [
                    {
                      "key": "pending",
                      "label": "ממתין לחתימה",
                      "bgColor": "#fef9c3",
                      "textColor": "#854d0e"
                    },
                    {
                      "key": "under_review",
                      "label": "בבדיקה",
                      "bgColor": "#ffedd5",
                      "textColor": "#c2410c"
                    },
                    {
                      "key": "completed",
                      "label": "נחתם",
                      "bgColor": "#dcfce7",
                      "textColor": "#166534"
                    },
                    {
                      "key": "rejected",
                      "label": "נדחה",
                      "bgColor": "#fee2e2",
                      "textColor": "#dc2626"
                    }
                  ],
                  "count": 4,
                  "list_type": "signature-document-statuses"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/lists/additional-expense-types": {
      "get": {
        "tags": [
          "Lists"
        ],
        "summary": "List additional expense types",
        "description": "Returns the types of additional transaction expenses (purchase tax, legal fees, brokerage, etc.).",
        "operationId": "getAdditionalExpenseTypes",
        "responses": {
          "200": {
            "description": "Additional expense types",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ListResponse"
                },
                "example": {
                  "data": [
                    {
                      "key": "purchase_tax",
                      "label": "מס רכישה"
                    },
                    {
                      "key": "lawyer_fee",
                      "label": "שכר טרחה עו\"ד"
                    },
                    {
                      "key": "brokerage",
                      "label": "תיווך"
                    },
                    {
                      "key": "mortgage_consulting",
                      "label": "ייעוץ משכנתאות"
                    },
                    {
                      "key": "renovation_furniture",
                      "label": "שיפוץ וריהוט"
                    },
                    {
                      "key": "index_addition",
                      "label": "תוספת עבור מדד"
                    },
                    {
                      "key": "appraisal",
                      "label": "שמאות"
                    },
                    {
                      "key": "other",
                      "label": "אחר"
                    }
                  ],
                  "count": 8,
                  "list_type": "additional-expense-types"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/lists/calendar-event-types": {
      "get": {
        "tags": [
          "Lists"
        ],
        "summary": "List calendar event types",
        "description": "Returns the calendar event types (task, reminder, meeting, etc.), with color, icon, and sort order.",
        "operationId": "getCalendarEventTypes",
        "responses": {
          "200": {
            "description": "Calendar event types",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CalendarEventTypeListResponse"
                },
                "example": {
                  "data": [
                    {
                      "code": "task",
                      "name": "משימה",
                      "nameEn": "Task",
                      "color": "#3b82f6",
                      "icon": "check-square",
                      "sortOrder": 1,
                      "showInCalendar": true,
                      "allowSync": true
                    },
                    {
                      "code": "reminder",
                      "name": "תזכורת",
                      "nameEn": "Reminder",
                      "color": "#f59e0b",
                      "icon": "bell",
                      "sortOrder": 2,
                      "showInCalendar": true,
                      "allowSync": true
                    },
                    {
                      "code": "payment",
                      "name": "תשלום",
                      "nameEn": "Payment",
                      "color": "#10b981",
                      "icon": "credit-card",
                      "sortOrder": 3,
                      "showInCalendar": true,
                      "allowSync": true
                    },
                    {
                      "code": "meeting",
                      "name": "פגישה",
                      "nameEn": "Meeting",
                      "color": "#8b5cf6",
                      "icon": "users",
                      "sortOrder": 4,
                      "showInCalendar": true,
                      "allowSync": true
                    },
                    {
                      "code": "deadline",
                      "name": "דד-ליין",
                      "nameEn": "Deadline",
                      "color": "#ef4444",
                      "icon": "alert-circle",
                      "sortOrder": 5,
                      "showInCalendar": true,
                      "allowSync": true
                    },
                    {
                      "code": "milestone",
                      "name": "אבן דרך",
                      "nameEn": "Milestone",
                      "color": "#06b6d4",
                      "icon": "flag",
                      "sortOrder": 6,
                      "showInCalendar": true,
                      "allowSync": true
                    },
                    {
                      "code": "call",
                      "name": "שיחה",
                      "nameEn": "Call",
                      "color": "#6366f1",
                      "icon": "phone",
                      "sortOrder": 7,
                      "showInCalendar": true,
                      "allowSync": true
                    },
                    {
                      "code": "document",
                      "name": "מסמך",
                      "nameEn": "Document",
                      "color": "#84cc16",
                      "icon": "file-text",
                      "sortOrder": 8,
                      "showInCalendar": true,
                      "allowSync": true
                    },
                    {
                      "code": "borrower_signatures",
                      "name": "חתימות לווים",
                      "nameEn": "Borrower Signatures",
                      "color": "#0ea5e9",
                      "icon": "pen-tool",
                      "sortOrder": 55,
                      "showInCalendar": true,
                      "allowSync": true
                    },
                    {
                      "code": "custom",
                      "name": "אחר",
                      "nameEn": "Other",
                      "color": "#6b7280",
                      "icon": "calendar",
                      "sortOrder": 99,
                      "showInCalendar": true,
                      "allowSync": true
                    }
                  ],
                  "count": 10,
                  "list_type": "calendar-event-types"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/contacts": {
      "get": {
        "tags": [
          "Contacts"
        ],
        "summary": "List contacts",
        "description": "Returns the organization's contacts (bankers, appraisers, lawyers, etc.), excluding deleted contacts, newest first, with pagination.",
        "operationId": "getContacts",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Partial, case-insensitive search across first name, last name, phone, email, and company. The characters , ( ) % _ \\ \" ' are removed from the search term before searching."
          },
          {
            "name": "type",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "banker",
                "appraiser",
                "lawyer",
                "insurance",
                "contractor",
                "other"
              ]
            },
            "description": "Filter by contact type"
          }
        ],
        "responses": {
          "200": {
            "description": "List of contacts",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Contact"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Total number of records matching the filter (not just those on the current page)"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "tags": [
          "Contacts"
        ],
        "summary": "Create a contact",
        "description": "Creates a contact in the organization.\n\n- Required: first_name, last_name, and type. A missing field returns 400 with a validation object.\n- type must be one of: banker, appraiser, lawyer, insurance, contractor, other. Otherwise, the API returns 400, and the value you sent is returned in provided_type. When type=other, you can specify the type in custom_type.",
        "operationId": "createContact",
        "requestBody": {
          "description": "Contact details",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateContact"
              },
              "example": {
                "first_name": "Michal",
                "last_name": "Avraham",
                "type": "banker",
                "company": "Example Bank",
                "job_title": "Mortgage banker",
                "phone": "03-0000000",
                "email": "michal.avraham@example.com",
                "notes": "Handles the branch's mortgage files"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Contact created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Contact"
                },
                "example": {
                  "id": "9e0f1a2b-3c4d-4e5f-a6b7-c8d9e0f1a2b3",
                  "organization_id": "0b8e1f2a-7c3d-4a5b-9e6f-2a3b4c5d6e7f",
                  "first_name": "Michal",
                  "last_name": "Avraham",
                  "type": "banker",
                  "company": "Example Bank",
                  "job_title": "Mortgage banker",
                  "phone": "03-0000000",
                  "email": "michal.avraham@example.com",
                  "notes": "Handles the branch's mortgage files",
                  "custom_type": null,
                  "created_at": "2026-10-14T08:15:22.481234+00:00",
                  "updated_at": "2026-10-14T08:15:22.481234+00:00"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/contacts/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string",
            "format": "uuid"
          },
          "description": "Contact ID"
        }
      ],
      "get": {
        "tags": [
          "Contacts"
        ],
        "summary": "Get a contact",
        "description": "Returns a contact by ID.",
        "operationId": "getContactById",
        "responses": {
          "200": {
            "description": "Contact details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Contact"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "put": {
        "tags": [
          "Contacts"
        ],
        "summary": "Update a contact",
        "description": "Partial update: only the fields you send are updated, including with PUT, which is identical to PATCH. type is validated against the list of allowed types (otherwise 400). If no updatable field is sent, the API returns 400.",
        "operationId": "replaceContact",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateContact"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated contact",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Contact"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "patch": {
        "tags": [
          "Contacts"
        ],
        "summary": "Partially update a contact",
        "description": "Partial update: only the fields you send are updated, including with PUT, which is identical to PATCH. type is validated against the list of allowed types (otherwise 400). If no updatable field is sent, the API returns 400.",
        "operationId": "updateContact",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateContact"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated contact",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Contact"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "delete": {
        "tags": [
          "Contacts"
        ],
        "summary": "Delete a contact",
        "description": "Soft delete: the contact is no longer returned in queries. A contact that is linked to a mortgage file cannot be deleted; the API returns 409 with related_mortgages_count. Unlink the contact from its mortgage files in the app first (the API does not provide an unlink operation).",
        "operationId": "deleteContact",
        "responses": {
          "200": {
            "description": "Contact deleted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteResult"
                },
                "example": {
                  "success": true,
                  "message": "Contact deleted successfully"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "The contact is linked to mortgage files. The number of links is returned in related_mortgages_count",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Cannot delete contact",
                  "details": "This contact is linked to active mortgage files. You must unlink them first.",
                  "status": 409,
                  "related_mortgages_count": 1
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/tasks": {
      "get": {
        "tags": [
          "Tasks"
        ],
        "summary": "List tasks",
        "description": "Returns the organization's tasks (excluding deleted tasks), each with a summary of its linked entity (mortgage_file / lead / customer, or null). Sorted by due_date in ascending order (tasks without a due date last), then from newest to oldest.",
        "operationId": "getTasks",
        "parameters": [
          {
            "name": "mortgage_file_id",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Only tasks linked to this mortgage file"
          },
          {
            "name": "lead_id",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Only tasks linked to this lead"
          },
          {
            "name": "customer_id",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Only tasks linked to this customer"
          },
          {
            "name": "standalone",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "true - only standalone tasks that are not linked to a mortgage file, lead, or customer"
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "open",
                "in_progress",
                "completed",
                "cancelled"
              ]
            },
            "description": "Filter by status"
          },
          {
            "name": "priority",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "low",
                "medium",
                "high"
              ]
            },
            "description": "Filter by priority"
          },
          {
            "name": "assigned_to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter by the user the task is assigned to"
          },
          {
            "name": "unassigned",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "true - only tasks that are not assigned to a user"
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Partial, case-insensitive search across title and description. The characters , ( ) % _ \\ \" ' are removed from the search term before searching."
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          }
        ],
        "responses": {
          "200": {
            "description": "List of tasks",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Task"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Total number of records matching the filter (not just those on the current page)"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "tags": [
          "Tasks"
        ],
        "summary": "Create a task",
        "description": "Creates a task. You can link it to a mortgage file, lead, and/or customer (mortgage_file_id / lead_id / customer_id), or create a standalone task without any of them.\n\n- Required: title (non-empty). Otherwise, the API returns 400.\n- Every entity ID you send must belong to an active record in the organization. Otherwise, the API returns 400.\n- Defaults: status=open, priority=medium.\n- status must be one of open, in_progress, completed, cancelled (otherwise 400); the legacy value done is accepted as completed. completed also sets completed_at.\n- parent_task_id must be a task in the organization (otherwise 400).\n- An assigned_to value that is not the ID of an active user in the organization is ignored.",
        "operationId": "createTask",
        "requestBody": {
          "description": "Task details",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTask"
              },
              "example": {
                "title": "Collect pay slips",
                "description": "Last three pay slips for both borrowers",
                "due_date": "2026-11-01T09:00:00+00:00",
                "priority": "high",
                "mortgage_file_id": "c4d5e6f7-8a9b-4c0d-9e1f-2a3b4c5d6e7f"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Task created (including a summary of the linked entity)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                },
                "example": {
                  "id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
                  "organization_id": "0b8e1f2a-7c3d-4a5b-9e6f-2a3b4c5d6e7f",
                  "mortgage_file_id": "c4d5e6f7-8a9b-4c0d-9e1f-2a3b4c5d6e7f",
                  "lead_id": null,
                  "customer_id": null,
                  "title": "Collect pay slips",
                  "description": "Last three pay slips for both borrowers",
                  "status": "open",
                  "priority": "high",
                  "due_date": "2026-11-01T09:00:00+00:00",
                  "assigned_to": null,
                  "parent_task_id": null,
                  "progress": 0,
                  "is_favorite": false,
                  "completed_at": null,
                  "created_at": "2026-10-14T08:15:22.481234+00:00",
                  "updated_at": "2026-10-14T08:15:22.481234+00:00",
                  "mortgage_file": {
                    "id": "c4d5e6f7-8a9b-4c0d-9e1f-2a3b4c5d6e7f",
                    "file_number": "2026-0042",
                    "title": "Apartment purchase - Cohen family",
                    "status": "setup"
                  },
                  "lead": null,
                  "customer": null
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/tasks/{taskId}": {
      "get": {
        "tags": [
          "Tasks"
        ],
        "summary": "Get a task",
        "description": "Returns a task by ID, including a summary of its linked entity.",
        "operationId": "getTask",
        "parameters": [
          {
            "name": "taskId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Task ID"
          }
        ],
        "responses": {
          "200": {
            "description": "The task",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "put": {
        "tags": [
          "Tasks"
        ],
        "summary": "Update a task",
        "description": "Partial update: only the fields you send are updated (PUT and PATCH behave identically). If no updatable field is sent, the API returns 400. This path also lets you replace or unlink (null) the linked entity: mortgage_file_id, lead_id, customer_id. Any ID you send must belong to an active record in the organization (otherwise 400). status follows the same rules as in creation: moving to completed sets completed_at, and moving away from completed clears it. parent_task_id must be another task in the organization (otherwise 400).",
        "operationId": "updateTask",
        "parameters": [
          {
            "name": "taskId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Task ID"
          }
        ],
        "requestBody": {
          "description": "Fields to update",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTask"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated task",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "patch": {
        "tags": [
          "Tasks"
        ],
        "summary": "Partially update a task",
        "description": "Partial update: only the fields you send are updated (PUT and PATCH behave identically). If no updatable field is sent, the API returns 400. This path also lets you replace or unlink (null) the linked entity: mortgage_file_id, lead_id, customer_id. Any ID you send must belong to an active record in the organization (otherwise 400). status follows the same rules as in creation: moving to completed sets completed_at, and moving away from completed clears it. parent_task_id must be another task in the organization (otherwise 400).",
        "operationId": "patchTask",
        "parameters": [
          {
            "name": "taskId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Task ID"
          }
        ],
        "requestBody": {
          "description": "Fields to update",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTask"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated task",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/tasks/{taskId}/status": {
      "patch": {
        "tags": [
          "Tasks"
        ],
        "summary": "Update a task's status",
        "description": "Updates only the status field: open, in_progress, completed or cancelled (the legacy value done is accepted as completed). Moving to completed sets completed_at, and moving away from completed clears it. A missing or unknown status returns 400.",
        "operationId": "patchTaskStatusTopLevel",
        "parameters": [
          {
            "name": "taskId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Task ID"
          }
        ],
        "requestBody": {
          "description": "The new status",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "open",
                      "in_progress",
                      "completed",
                      "cancelled"
                    ]
                  }
                },
                "required": [
                  "status"
                ]
              },
              "example": {
                "status": "completed"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated task",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/timeline": {
      "get": {
        "tags": [
          "Timeline"
        ],
        "summary": "Get a mortgage file's timeline",
        "description": "Returns the mortgage file's timeline events, newest first, with pagination. Read-only.",
        "operationId": "getMortgageFileTimeline",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "event_type",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter by event type: a value from the system's event types, for example status_updated, note_added, task_created, task_completed, charge_created, payment_received"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          }
        ],
        "responses": {
          "200": {
            "description": "Timeline events",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TimelineEvent"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Total number of records matching the filter (not just those on the current page)"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/status-history": {
      "get": {
        "tags": [
          "Timeline"
        ],
        "summary": "Get a mortgage file's status history",
        "description": "Same as /timeline, filtered to status change events (event type status_updated and, for older records, status_change).",
        "operationId": "getMortgageFileStatusHistory",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          }
        ],
        "responses": {
          "200": {
            "description": "Timeline events",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TimelineEvent"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Total number of records matching the filter (not just those on the current page)"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/tasks": {
      "get": {
        "tags": [
          "Tasks"
        ],
        "summary": "List a mortgage file's tasks",
        "description": "Same as GET /tasks, limited to the mortgage file's tasks. Sorted by due_date in ascending order (tasks without a due date last), then from newest to oldest.",
        "operationId": "getMortgageFileTasks",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "open",
                "in_progress",
                "completed",
                "cancelled"
              ]
            },
            "description": "Filter by status"
          },
          {
            "name": "priority",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "low",
                "medium",
                "high"
              ]
            },
            "description": "Filter by priority"
          },
          {
            "name": "assigned_to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter by the user the task is assigned to"
          },
          {
            "name": "unassigned",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "true - only tasks that are not assigned to a user"
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Partial, case-insensitive search across title and description. The characters , ( ) % _ \\ \" ' are removed from the search term before searching."
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          }
        ],
        "responses": {
          "200": {
            "description": "The mortgage file's tasks",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Task"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Total number of records matching the filter (not just those on the current page)"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "tags": [
          "Tasks"
        ],
        "summary": "Create a task in a mortgage file",
        "description": "Creates a task linked to the mortgage file in the path. title is required (otherwise 400). mortgage_file_id, lead_id, and customer_id in the request body are ignored. status and parent_task_id follow the same rules as in POST /tasks. Defaults: status=open, priority=medium.",
        "operationId": "createMortgageFileTask",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          }
        ],
        "requestBody": {
          "description": "Task details",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTask"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Task created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/tasks/{taskId}": {
      "get": {
        "tags": [
          "Tasks"
        ],
        "summary": "Get a mortgage file task",
        "description": "Returns a task of the mortgage file by ID.",
        "operationId": "getMortgageFileTask",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "taskId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Task ID"
          }
        ],
        "responses": {
          "200": {
            "description": "The task",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "put": {
        "tags": [
          "Tasks"
        ],
        "summary": "Update a mortgage file task",
        "description": "Partial update: only the fields you send are updated (PUT and PATCH behave identically). If no updatable field is sent, the API returns 400. This path cannot change the linked entities (mortgage_file_id, lead_id, customer_id); to do so, use PUT /tasks/{taskId}. status follows the same rules as in creation: moving to completed sets completed_at, and moving away from completed clears it. parent_task_id must be another task in the organization (otherwise 400).",
        "operationId": "updateMortgageFileTask",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "taskId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Task ID"
          }
        ],
        "requestBody": {
          "description": "Fields to update",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTask"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated task",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "patch": {
        "tags": [
          "Tasks"
        ],
        "summary": "Partially update a mortgage file task",
        "description": "Partial update: only the fields you send are updated (PUT and PATCH behave identically). If no updatable field is sent, the API returns 400. This path cannot change the linked entities (mortgage_file_id, lead_id, customer_id); to do so, use PUT /tasks/{taskId}. status follows the same rules as in creation: moving to completed sets completed_at, and moving away from completed clears it. parent_task_id must be another task in the organization (otherwise 400).",
        "operationId": "patchMortgageFileTask",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "taskId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Task ID"
          }
        ],
        "requestBody": {
          "description": "Fields to update",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTask"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated task",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/tasks/{taskId}/status": {
      "patch": {
        "tags": [
          "Tasks"
        ],
        "summary": "Update a mortgage file task's status",
        "description": "Updates only the status field: open, in_progress, completed or cancelled (the legacy value done is accepted as completed). Moving to completed sets completed_at, and moving away from completed clears it. A missing or unknown status returns 400.",
        "operationId": "patchMortgageFileTaskStatus",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "taskId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Task ID"
          }
        ],
        "requestBody": {
          "description": "The new status",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "open",
                      "in_progress",
                      "completed",
                      "cancelled"
                    ]
                  }
                },
                "required": [
                  "status"
                ]
              },
              "example": {
                "status": "completed"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated task",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Task"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/notes": {
      "get": {
        "tags": [
          "Notes"
        ],
        "summary": "List a mortgage file's notes",
        "description": "Returns pinned notes (is_pinned) first, followed by the rest from newest to oldest. Deleted notes are excluded.",
        "operationId": "getMortgageFileNotes",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Partial, case-insensitive search across title and content. The characters , ( ) % _ \\ \" ' are removed from the search term before searching."
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          }
        ],
        "responses": {
          "200": {
            "description": "The mortgage file's notes",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Note"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Total number of records matching the filter (not just those on the current page)"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "tags": [
          "Notes"
        ],
        "summary": "Create a note in a mortgage file",
        "description": "content is required and must not be empty. Otherwise, the API returns 400.",
        "operationId": "createMortgageFileNote",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          }
        ],
        "requestBody": {
          "description": "Note details",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateNote"
              },
              "example": {
                "title": "Call with the bank",
                "content": "The bank requested an up-to-date balance confirmation for the existing mortgage",
                "is_pinned": true
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Note created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Note"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/notes/{noteId}": {
      "get": {
        "tags": [
          "Notes"
        ],
        "summary": "Get a note",
        "description": "Returns a note of the mortgage file by ID.",
        "operationId": "getMortgageFileNote",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "noteId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Note ID"
          }
        ],
        "responses": {
          "200": {
            "description": "The note",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Note"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "put": {
        "tags": [
          "Notes"
        ],
        "summary": "Update a note",
        "description": "Partial update: only the fields you send are updated (PUT and PATCH behave identically). If no updatable field is sent, the API returns 400. is_completed=true also sets completed_at. A locked note (is_locked=true) returns 409 unless the request unlocks it (is_locked: false); the unlock can be combined with other changes in the same request.",
        "operationId": "updateMortgageFileNote",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "noteId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Note ID"
          }
        ],
        "requestBody": {
          "description": "Fields to update",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateNote"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated note",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Note"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "The note is locked (is_locked=true) and the request does not unlock it",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Note is locked",
                  "details": "Unlock the note before editing",
                  "status": 409
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "patch": {
        "tags": [
          "Notes"
        ],
        "summary": "Partially update a note",
        "description": "Partial update: only the fields you send are updated (PUT and PATCH behave identically). If no updatable field is sent, returns 400. Setting is_completed=true also sets completed_at. A locked note (is_locked=true) returns 409 unless the request unlocks it (is_locked: false); the unlock can be combined with other changes in the same request.",
        "operationId": "patchMortgageFileNote",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "noteId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The note ID"
          }
        ],
        "requestBody": {
          "description": "The fields to update",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateNote"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated note",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Note"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "The note is locked (is_locked=true) and the request does not unlock it",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Note is locked",
                  "details": "Unlock the note before editing",
                  "status": 409
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/contacts": {
      "get": {
        "tags": [
          "File contacts"
        ],
        "summary": "List a mortgage file's contacts",
        "description": "Returns the active contact links for the mortgage file, newest first, each with the contact's details (contact).",
        "operationId": "getMortgageFileContacts",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          }
        ],
        "responses": {
          "200": {
            "description": "The contact links",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/MortgageContactLink"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Total number of records matching the filter (not just those on the current page)"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "tags": [
          "File contacts"
        ],
        "summary": "Link a contact to a mortgage file",
        "description": "contact_id is required (otherwise 400) and must belong to an active contact in the organization (otherwise 404). If the contact is already linked to the mortgage file, returns 409 with the existing link's ID in existing_link_id.",
        "operationId": "linkMortgageFileContact",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "contact_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "The contact ID"
                  },
                  "notes": {
                    "type": "string",
                    "description": "Notes for the link"
                  }
                },
                "required": [
                  "contact_id"
                ]
              },
              "example": {
                "contact_id": "9e0f1a2b-3c4d-4e5f-a6b7-c8d9e0f1a2b3",
                "notes": "The banker handling the file"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The link was created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MortgageContactLink"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "The contact is already linked to the mortgage file. The existing link's ID is returned in existing_link_id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Contact already linked",
                  "details": "Use PUT to update link notes",
                  "status": 409,
                  "existing_link_id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/contacts/{linkId}": {
      "put": {
        "tags": [
          "File contacts"
        ],
        "summary": "Update a file contact's notes",
        "description": "Only notes can be updated (PUT and PATCH behave identically). A request without notes returns 400.",
        "operationId": "updateMortgageFileContactLink",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "linkId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The link ID (the id from the mortgage file's contacts list, not the contact ID)"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "notes": {
                    "type": "string",
                    "description": "Notes for the link"
                  }
                }
              },
              "example": {
                "notes": "The banker handling the file"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated link",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MortgageContactLink"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "patch": {
        "tags": [
          "File contacts"
        ],
        "summary": "Partially update a file contact's notes",
        "description": "Only notes can be updated (PUT and PATCH behave identically). A request without notes returns 400.",
        "operationId": "patchMortgageFileContactLink",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "linkId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The link ID (the id from the mortgage file's contacts list, not the contact ID)"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "notes": {
                    "type": "string",
                    "description": "Notes for the link"
                  }
                }
              },
              "example": {
                "notes": "The banker handling the file"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated link",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MortgageContactLink"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/watchers": {
      "get": {
        "tags": [
          "Watchers"
        ],
        "summary": "List a mortgage file's watchers",
        "description": "Returns the users watching the mortgage file, newest first, each with the user's details (watcher).",
        "operationId": "getMortgageFileWatchers",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          }
        ],
        "responses": {
          "200": {
            "description": "The watchers",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Watcher"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Total number of records matching the filter (not just those on the current page)"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "tags": [
          "Watchers"
        ],
        "summary": "Add a watcher to a mortgage file",
        "description": "watcher_id is required (otherwise 400) and must be the ID of an active user in the organization (otherwise 404). If the user is already watching, returns 409 with the existing record's ID in existing_id. The API does not provide a remove operation.",
        "operationId": "addMortgageFileWatcher",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "watcher_id": {
                    "type": "string",
                    "format": "uuid",
                    "description": "ID of the user (profile) who will watch the mortgage file"
                  }
                },
                "required": [
                  "watcher_id"
                ]
              },
              "example": {
                "watcher_id": "4d5e6f7a-8b9c-4d0e-9f1a-2b3c4d5e6f7a"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The watcher was added",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Watcher"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "The user is already watching the mortgage file. The existing record's ID is returned in existing_id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Watcher already attached",
                  "status": 409,
                  "existing_id": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/documents": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "List a mortgage file's documents",
        "description": "Returns metadata for the customer's documents in the mortgage file, newest first. Read-only: file contents are not available through the API.",
        "operationId": "getMortgageFileDocuments",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "borrower_id",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter by borrower"
          },
          {
            "name": "category",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter by category (exact match)"
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Partial, case-insensitive search on the original file name and category. The characters , ( ) % _ \\ \" ' are stripped from the term before searching."
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          }
        ],
        "responses": {
          "200": {
            "description": "The mortgage file's documents",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ClientDocument"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Total number of records matching the filter (not just those on the current page)"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/documents/{docId}": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "Get a document",
        "description": "Returns the metadata of a document in the mortgage file by ID.",
        "operationId": "getMortgageFileDocument",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "docId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The document ID"
          }
        ],
        "responses": {
          "200": {
            "description": "The document",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientDocument"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/signatures": {
      "get": {
        "tags": [
          "Signatures"
        ],
        "summary": "List a mortgage file's signatures",
        "description": "Returns the signature records for documents that belong to the mortgage file, newest first, each with the document's details (document). Read-only.",
        "operationId": "getMortgageFileSignatures",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          }
        ],
        "responses": {
          "200": {
            "description": "The signatures",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/DocumentSignature"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Total number of records matching the filter (not just those on the current page)"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/generated-documents": {
      "get": {
        "tags": [
          "Generated documents"
        ],
        "summary": "List a mortgage file's generated documents",
        "description": "Returns the documents generated from templates for the mortgage file, newest first. Read-only.",
        "operationId": "getMortgageFileGeneratedDocuments",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter by document status"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          }
        ],
        "responses": {
          "200": {
            "description": "The generated documents",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/GeneratedDocument"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Total number of records matching the filter (not just those on the current page)"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/generated-documents/{docId}": {
      "get": {
        "tags": [
          "Generated documents"
        ],
        "summary": "Get a generated document",
        "description": "Returns a document generated from a template for the mortgage file, by ID.",
        "operationId": "getMortgageFileGeneratedDocument",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "docId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The generated document ID"
          }
        ],
        "responses": {
          "200": {
            "description": "The document",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GeneratedDocument"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/document-statuses": {
      "get": {
        "tags": [
          "Document statuses"
        ],
        "summary": "List a mortgage file's document statuses",
        "description": "Returns the tracking rows for documents requested from the mortgage file's borrowers (including documents for signature), newest first. Rows are created by the system; the API does not support creating or deleting them.",
        "operationId": "getMortgageFileDocumentStatuses",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "uploading",
                "under_review",
                "completed",
                "rejected"
              ]
            },
            "description": "Filter by status"
          },
          {
            "name": "borrower_id",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter by borrower"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          }
        ],
        "responses": {
          "200": {
            "description": "The document statuses",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ClientDocumentStatus"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Total number of records matching the filter (not just those on the current page)"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/document-statuses/{statusId}": {
      "put": {
        "tags": [
          "Document statuses"
        ],
        "summary": "Update a document status",
        "description": "Only status and notes can be updated (PUT and PATCH behave identically). If neither is sent, returns 400.",
        "operationId": "updateMortgageFileDocumentStatus",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "statusId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The status row ID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "pending",
                      "uploading",
                      "under_review",
                      "completed",
                      "rejected"
                    ],
                    "description": "The new status"
                  },
                  "notes": {
                    "type": "object",
                    "description": "Replaces the entire stored notes object (including status_history)"
                  }
                }
              },
              "example": {
                "status": "completed"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated status row",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientDocumentStatus"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "patch": {
        "tags": [
          "Document statuses"
        ],
        "summary": "Partially update a document status",
        "description": "Only status and notes can be updated (PUT and PATCH behave identically). If neither is sent, returns 400.",
        "operationId": "patchMortgageFileDocumentStatus",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "statusId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The status row ID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "pending",
                      "uploading",
                      "under_review",
                      "completed",
                      "rejected"
                    ],
                    "description": "The new status"
                  },
                  "notes": {
                    "type": "object",
                    "description": "Replaces the entire stored notes object (including status_history)"
                  }
                }
              },
              "example": {
                "status": "completed"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated status row",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientDocumentStatus"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/reminders": {
      "get": {
        "tags": [
          "Reminders"
        ],
        "summary": "List a mortgage file's reminders",
        "description": "Returns the mortgage file's reminders, sorted by remind_at (earliest first). By default, only reminders that have not yet been sent or dismissed are returned.",
        "operationId": "getMortgageFileReminders",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "include_sent",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "If true, also includes reminders that have already been sent"
          },
          {
            "name": "include_dismissed",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "If true, also includes dismissed reminders"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          }
        ],
        "responses": {
          "200": {
            "description": "The mortgage file's reminders",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Reminder"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Total number of records matching the filter (not just those on the current page)"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "tags": [
          "Reminders"
        ],
        "summary": "Create a reminder for a mortgage file",
        "description": "Required: title (non-empty) and remind_at (an ISO 8601 timestamp); otherwise returns 400. channels defaults to [\"notification\"]. recipient_user_id (optional) must be a user in the organization (otherwise 400).",
        "operationId": "createMortgageFileReminder",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          }
        ],
        "requestBody": {
          "description": "The reminder details",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateReminder"
              },
              "example": {
                "title": "Follow up with the bank on the approval in principle",
                "remind_at": "2026-10-20T07:00:00+00:00",
                "recipient_user_id": "4d5e6f7a-8b9c-4d0e-9f1a-2b3c4d5e6f7a"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The reminder was created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Reminder"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/reminders/{reminderId}": {
      "get": {
        "tags": [
          "Reminders"
        ],
        "summary": "Get a reminder",
        "description": "Returns a reminder of the mortgage file by ID.",
        "operationId": "getMortgageFileReminder",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "reminderId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The reminder ID"
          }
        ],
        "responses": {
          "200": {
            "description": "The reminder",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Reminder"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "put": {
        "tags": [
          "Reminders"
        ],
        "summary": "Update a reminder",
        "description": "Partial update: only the fields you send are updated (PUT and PATCH behave identically). If no updatable field is sent, returns 400. Setting is_dismissed=true also sets dismissed_at. recipient_user_id, if sent, must be a user in the organization (otherwise 400).",
        "operationId": "updateMortgageFileReminder",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "reminderId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The reminder ID"
          }
        ],
        "requestBody": {
          "description": "The fields to update",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateReminder"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated reminder",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Reminder"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "patch": {
        "tags": [
          "Reminders"
        ],
        "summary": "Partially update a reminder",
        "description": "Partial update: only the fields you send are updated (PUT and PATCH behave identically). If no updatable field is sent, returns 400. Setting is_dismissed=true also sets dismissed_at. recipient_user_id, if sent, must be a user in the organization (otherwise 400).",
        "operationId": "patchMortgageFileReminder",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "reminderId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The reminder ID"
          }
        ],
        "requestBody": {
          "description": "The fields to update",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateReminder"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated reminder",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Reminder"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/charges": {
      "get": {
        "tags": [
          "Charges"
        ],
        "summary": "List a mortgage file's charges",
        "description": "Returns the mortgage file's charges, sorted by due_date in ascending order (charges without a date come last), then newest first.",
        "operationId": "getMortgageFileCharges",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "partial",
                "paid",
                "cancelled"
              ]
            },
            "description": "Filter by status"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          }
        ],
        "responses": {
          "200": {
            "description": "The mortgage file's charges",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/MortgageCharge"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Total number of records matching the filter (not just those on the current page)"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "tags": [
          "Charges"
        ],
        "summary": "Create a charge",
        "description": "Required: item_name (non-empty) and amount (a non-negative number); otherwise returns 400. Defaults: status=pending, includes_vat=true, is_ancillary_charge=false, milestone_due_offset_days=0.\n\n**Milestone link:** milestone_id and milestone_status_key together identify a milestone in the mortgage file. Send both or neither; sending only one returns 400 (Invalid milestone link). When the linked milestone is marked as completed, due_date is set automatically to the completion date + milestone_due_offset_days (for charges with status pending or partial), and linking to a milestone that is already completed sets the date immediately. A manually entered date is never overwritten; the source of the date is shown in due_date_source.",
        "operationId": "createMortgageFileCharge",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          }
        ],
        "requestBody": {
          "description": "The charge details",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateMortgageCharge"
              },
              "example": {
                "item_name": "Advisory fee - stage 2",
                "amount": 4500,
                "includes_vat": true,
                "is_ancillary_charge": false,
                "milestone_id": "8f9a0b1c-2d3e-4f5a-9b6c-7d8e9f0a1b2c",
                "milestone_status_key": "pending_approval",
                "milestone_due_offset_days": 3
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The charge was created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MortgageCharge"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/charges/{chargeId}": {
      "get": {
        "tags": [
          "Charges"
        ],
        "summary": "Get a charge",
        "description": "Returns a charge of the mortgage file by ID.",
        "operationId": "getMortgageFileCharge",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "chargeId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The charge ID"
          }
        ],
        "responses": {
          "200": {
            "description": "The charge",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MortgageCharge"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "put": {
        "tags": [
          "Charges"
        ],
        "summary": "Update a charge",
        "description": "Partial update: only the fields you send are updated (PUT and PATCH behave identically). If no updatable field is sent, returns 400. A charge for which an external document has been issued (external_document_id) is locked for editing and returns 409.\n\nThe both-or-neither rule for the milestone link is evaluated against the merged result (the stored values combined with the request): you can change both together, or remove the link by setting both to null. Updating due_date through the API marks it as manual (due_date_source=manual).\n\namount, if sent, must be a non-negative number (otherwise 400).",
        "operationId": "updateMortgageFileCharge",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "chargeId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The charge ID"
          }
        ],
        "requestBody": {
          "description": "The fields to update",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateMortgageCharge"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated charge",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MortgageCharge"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "An external document (external_document_id) has already been issued for the charge, so it is locked for editing",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Charge has an issued document",
                  "details": "Cannot edit a charge after an external document was issued; cancel via the billing integration instead",
                  "status": 409
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "patch": {
        "tags": [
          "Charges"
        ],
        "summary": "Partially update a charge",
        "description": "Partial update: only the fields you send are updated (PUT and PATCH behave identically). If no updatable field is sent, returns 400. A charge for which an external document has been issued (external_document_id) is locked for editing and returns 409.\n\nThe both-or-neither rule for the milestone link is evaluated against the merged result (the stored values combined with the request): you can change both together, or remove the link by setting both to null. Updating due_date through the API marks it as manual (due_date_source=manual).\n\namount, if sent, must be a non-negative number (otherwise 400).",
        "operationId": "patchMortgageFileCharge",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "chargeId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The charge ID"
          }
        ],
        "requestBody": {
          "description": "The fields to update",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateMortgageCharge"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated charge",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MortgageCharge"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "An external document (external_document_id) has already been issued for the charge, so it is locked for editing",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Charge has an issued document",
                  "details": "Cannot edit a charge after an external document was issued; cancel via the billing integration instead",
                  "status": 409
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/payments": {
      "get": {
        "tags": [
          "Payments"
        ],
        "summary": "List a mortgage file's payments",
        "description": "Returns the mortgage file's payments, sorted by payment_date, newest first. Cancelled payments are excluded by default.",
        "operationId": "getMortgageFilePayments",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "charge_id",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Filter by charge"
          },
          {
            "name": "include_cancelled",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "If true, also includes cancelled payments"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          }
        ],
        "responses": {
          "200": {
            "description": "The mortgage file's payments",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/MortgagePayment"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Total number of records matching the filter (not just those on the current page)"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "tags": [
          "Payments"
        ],
        "summary": "Record a payment",
        "description": "Required: amount (a positive number), payment_date (YYYY-MM-DD), and payment_source; otherwise returns 400. charge_id (optional) must be a charge of the same mortgage file; otherwise returns 400.",
        "operationId": "createMortgageFilePayment",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          }
        ],
        "requestBody": {
          "description": "The payment details",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateMortgagePayment"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The payment was recorded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MortgagePayment"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/payments/{paymentId}": {
      "get": {
        "tags": [
          "Payments"
        ],
        "summary": "Get a payment",
        "description": "Returns a payment of the mortgage file by ID.",
        "operationId": "getMortgageFilePayment",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "paymentId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The payment ID"
          }
        ],
        "responses": {
          "200": {
            "description": "The payment",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MortgagePayment"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "put": {
        "tags": [
          "Payments"
        ],
        "summary": "Update a payment",
        "description": "Partial update: only the fields you send are updated (PUT and PATCH behave identically). If no updatable field is sent, returns 400. A payment that has been cancelled, or for which a receipt has been issued (external_document_id), is locked for editing and returns 409. amount, if sent, must be a positive number, and charge_id must be a charge of the same mortgage file (otherwise 400).",
        "operationId": "updateMortgageFilePayment",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "paymentId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The payment ID"
          }
        ],
        "requestBody": {
          "description": "The fields to update",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateMortgagePayment"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated payment",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MortgagePayment"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "The payment has been cancelled, or a receipt has been issued for it (external_document_id), so it is locked for editing",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Payment is cancelled",
                  "details": "Cannot update a cancelled payment",
                  "status": 409
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "patch": {
        "tags": [
          "Payments"
        ],
        "summary": "Partially update a payment",
        "description": "Partial update: only the fields you send are updated (PUT and PATCH behave identically). If no updatable field is sent, returns 400. A payment that has been cancelled, or for which a receipt has been issued (external_document_id), is locked for editing and returns 409. amount, if sent, must be a positive number, and charge_id must be a charge of the same mortgage file (otherwise 400).",
        "operationId": "patchMortgageFilePayment",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "paymentId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The payment ID"
          }
        ],
        "requestBody": {
          "description": "The fields to update",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateMortgagePayment"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated payment",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MortgagePayment"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "The payment has been cancelled, or a receipt has been issued for it (external_document_id), so it is locked for editing",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "Payment is cancelled",
                  "details": "Cannot update a cancelled payment",
                  "status": 409
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/analysis": {
      "get": {
        "tags": [
          "File analysis"
        ],
        "summary": "List a mortgage file's analyses",
        "description": "Returns the analyses saved on the mortgage file, newest first.",
        "operationId": "getMortgageFileAnalyses",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          }
        ],
        "responses": {
          "200": {
            "description": "The mortgage file's analyses",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/MortgageAnalysis"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Total number of records matching the filter (not just those on the current page)"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "tags": [
          "File analysis"
        ],
        "summary": "Save a file analysis",
        "description": "analysis_data is required and must be a free-form JSON object (otherwise 400). The API does not support updating or deleting an analysis.",
        "operationId": "createMortgageFileAnalysis",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "analysis_data": {
                    "type": "object",
                    "description": "The analysis content (free-form JSON)"
                  }
                },
                "required": [
                  "analysis_data"
                ]
              },
              "example": {
                "analysis_data": {
                  "summary": "Repayment-to-income ratio 31%",
                  "max_monthly_payment": 8200
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The analysis was saved",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MortgageAnalysis"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/analysis/{analysisId}": {
      "get": {
        "tags": [
          "File analysis"
        ],
        "summary": "Get a file analysis",
        "description": "Returns a saved analysis of the mortgage file by ID.",
        "operationId": "getMortgageFileAnalysis",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "analysisId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The analysis ID"
          }
        ],
        "responses": {
          "200": {
            "description": "The analysis",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MortgageAnalysis"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/calculator-mixes": {
      "get": {
        "tags": [
          "Calculator mixes"
        ],
        "summary": "List a mortgage file's calculator mixes",
        "description": "Returns the mixes saved on the mortgage file, sorted by last update (most recent first).",
        "operationId": "getMortgageFileCalculatorMixes",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "source",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "internal",
                "smartnpv"
              ]
            },
            "description": "Filter by mix source"
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Partial, case-insensitive search on the name and description. The characters , ( ) % _ \\ \" ' are stripped from the term before searching."
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          }
        ],
        "responses": {
          "200": {
            "description": "The mortgage file's mixes",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CalculatorMix"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Total number of records matching the filter (not just those on the current page)"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "tags": [
          "Calculator mixes"
        ],
        "summary": "Create a calculator mix",
        "description": "name is required (non-empty); otherwise returns 400. source: internal (default) or smartnpv; any other value returns 400.",
        "operationId": "createMortgageFileCalculatorMix",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          }
        ],
        "requestBody": {
          "description": "The mix details",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCalculatorMix"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The mix was created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CalculatorMix"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/calculator-mixes/{mixId}": {
      "get": {
        "tags": [
          "Calculator mixes"
        ],
        "summary": "Get a calculator mix",
        "description": "Returns a mix of the mortgage file by ID.",
        "operationId": "getMortgageFileCalculatorMix",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "mixId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The mix ID"
          }
        ],
        "responses": {
          "200": {
            "description": "The mix",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CalculatorMix"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "put": {
        "tags": [
          "Calculator mixes"
        ],
        "summary": "Update a calculator mix",
        "description": "Partial update: only the fields you send are updated (PUT and PATCH behave identically). If no updatable field is sent, returns 400. source must be internal or smartnpv; otherwise returns 400.",
        "operationId": "updateMortgageFileCalculatorMix",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "mixId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The mix ID"
          }
        ],
        "requestBody": {
          "description": "The fields to update",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCalculatorMix"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated mix",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CalculatorMix"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "patch": {
        "tags": [
          "Calculator mixes"
        ],
        "summary": "Partially update a calculator mix",
        "description": "Partial update: only the fields you send are updated (PUT and PATCH behave identically). If no updatable field is sent, returns 400. source must be internal or smartnpv; otherwise returns 400.",
        "operationId": "patchMortgageFileCalculatorMix",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "mixId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The mix ID"
          }
        ],
        "requestBody": {
          "description": "The fields to update",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCalculatorMix"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated mix",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CalculatorMix"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/custom-fields": {
      "get": {
        "tags": [
          "Custom fields"
        ],
        "summary": "List a mortgage file's custom fields",
        "description": "Returns all of the organization's active custom field definitions for mortgage files (ordered by display_order), each with its current value in the mortgage file (value, or null). Not paginated.",
        "operationId": "getMortgageFileCustomFields",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          }
        ],
        "responses": {
          "200": {
            "description": "The definitions and values",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CustomFieldWithValue"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items in the data array"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/custom-fields/{customFieldId}": {
      "put": {
        "tags": [
          "Custom fields"
        ],
        "summary": "Set a custom field value",
        "description": "Creates or updates the field's value in the mortgage file (PUT and PATCH behave identically). field_value is required; otherwise returns 400. A definition that does not exist in the organization returns 404; a definition that is not for mortgage files returns 400.",
        "operationId": "upsertMortgageFileCustomField",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "customFieldId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The field definition ID (the id from GET /custom-fields)"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "field_value": {
                    "type": "string",
                    "nullable": true,
                    "description": "The value to save; null clears the value"
                  }
                },
                "required": [
                  "field_value"
                ]
              },
              "example": {
                "field_value": "Example Bank"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The saved value",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomFieldValue"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "patch": {
        "tags": [
          "Custom fields"
        ],
        "summary": "Set a custom field value (PATCH)",
        "description": "Creates or updates the field's value in the mortgage file (PUT and PATCH behave identically). field_value is required; otherwise returns 400. A definition that does not exist in the organization returns 404; a definition that is not for mortgage files returns 400.",
        "operationId": "patchMortgageFileCustomField",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "customFieldId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The field definition ID (the id from GET /custom-fields)"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "field_value": {
                    "type": "string",
                    "nullable": true,
                    "description": "The value to save; null clears the value"
                  }
                },
                "required": [
                  "field_value"
                ]
              },
              "example": {
                "field_value": "Example Bank"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The saved value",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomFieldValue"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/milestones": {
      "get": {
        "tags": [
          "Milestones"
        ],
        "summary": "List a mortgage file's milestones",
        "description": "Returns **all** of the mortgage file's milestones as they appear in the app: for each status in the organization's configuration, its milestones (both the organization's milestones and the file's custom milestones, is_custom=true), each with its progress row (progress, or null) and its checklist items.\n\nUnlike /milestones/progress, which returns only progress rows that have already been created, this endpoint returns the definitions even for a new mortgage file. Up to 2,000 rows are fetched from each table; summary.truncated=true indicates that the result was truncated.",
        "operationId": "getMortgageFileMilestonesOverview",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          }
        ],
        "responses": {
          "200": {
            "description": "Combined view",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MilestonesOverview"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/required-documents": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "List a mortgage file's document requirements",
        "description": "Returns **all** of the organization's document requirement definitions (categories and documents), with each document enriched with the status rows already created for it in the mortgage file (per borrower).\n\nUnlike /document-statuses, which returns only rows that have already been created, this endpoint returns the definitions even for a mortgage file in which no requirements have been created yet. The definitions are not filtered by their conditions (employment type, loan purpose, etc.); filtering is the consumer's responsibility. Up to 2,000 status rows are fetched; summary.truncated=true indicates that the result was truncated.",
        "operationId": "getMortgageFileRequiredDocuments",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          }
        ],
        "responses": {
          "200": {
            "description": "Combined view",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RequiredDocumentsOverview"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/milestones/custom": {
      "get": {
        "tags": [
          "Milestones"
        ],
        "summary": "List a mortgage file's custom milestones",
        "description": "Returns the milestones added to this mortgage file only, sorted by custom_order. Not paginated.",
        "operationId": "getMortgageFileCustomMilestones",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          }
        ],
        "responses": {
          "200": {
            "description": "The custom milestones",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CustomFileMilestone"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Number of items in the data array"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "tags": [
          "Milestones"
        ],
        "summary": "Create a custom milestone",
        "description": "Adds a milestone to this mortgage file only. Required: status_key (the key of the status the milestone belongs to) and label; otherwise returns 400.",
        "operationId": "createMortgageFileCustomMilestone",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          }
        ],
        "requestBody": {
          "description": "The milestone details",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCustomFileMilestone"
              },
              "example": {
                "status_key": "signing",
                "label": "Sign insurance documents",
                "linked_type": "none",
                "is_required": true
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The milestone was created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomFileMilestone"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/milestones/custom/{milestoneId}": {
      "put": {
        "tags": [
          "Milestones"
        ],
        "summary": "Update a custom milestone",
        "description": "Partial update: only the fields you send are updated (PUT and PATCH behave identically). If no updatable field is sent, returns 400.",
        "operationId": "updateMortgageFileCustomMilestone",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "milestoneId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The custom milestone ID"
          }
        ],
        "requestBody": {
          "description": "The fields to update",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCustomFileMilestone"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated milestone",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomFileMilestone"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "patch": {
        "tags": [
          "Milestones"
        ],
        "summary": "Partially update a custom milestone",
        "description": "Partial update: only the fields you send are updated (PUT and PATCH behave identically). If no updatable field is sent, returns 400.",
        "operationId": "patchMortgageFileCustomMilestone",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "milestoneId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The custom milestone ID"
          }
        ],
        "requestBody": {
          "description": "The fields to update",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCustomFileMilestone"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated milestone",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomFileMilestone"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/milestones/progress": {
      "get": {
        "tags": [
          "Milestones"
        ],
        "summary": "List milestone progress",
        "description": "Returns the progress rows already created in the mortgage file, sorted by custom_order.",
        "operationId": "getMortgageFileMilestoneProgress",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "status_key",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter by status key"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          }
        ],
        "responses": {
          "200": {
            "description": "The progress rows",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/MilestoneProgress"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Total number of records matching the filter (not just those on the current page)"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/milestones/progress/{progressId}": {
      "put": {
        "tags": [
          "Milestones"
        ],
        "summary": "Update milestone progress",
        "description": "Partial update: only the fields you send are updated (PUT and PATCH behave identically). If no updatable field is sent, returns 400. Setting is_completed=true sets completed_at and sets completion_percentage=100 (unless another value is sent); is_completed=false clears completed_at. Completing a milestone may set the due_date of charges linked to it.",
        "operationId": "updateMortgageFileMilestoneProgress",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "progressId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The progress row ID"
          }
        ],
        "requestBody": {
          "description": "The fields to update",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateMilestoneProgress"
              },
              "example": {
                "is_completed": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated progress row",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MilestoneProgress"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "patch": {
        "tags": [
          "Milestones"
        ],
        "summary": "Partially update milestone progress",
        "description": "Partial update: only the fields you send are updated (PUT and PATCH behave identically). If no updatable field is sent, returns 400. Setting is_completed=true sets completed_at and sets completion_percentage=100 (unless another value is sent); is_completed=false clears completed_at. Completing a milestone may set the due_date of charges linked to it.",
        "operationId": "patchMortgageFileMilestoneProgress",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "progressId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The progress row ID"
          }
        ],
        "requestBody": {
          "description": "The fields to update",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateMilestoneProgress"
              },
              "example": {
                "is_completed": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated progress row",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MilestoneProgress"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/milestones/checklist": {
      "get": {
        "tags": [
          "Milestones"
        ],
        "summary": "List milestone checklist items",
        "description": "Returns the checklist items of the mortgage file's milestones, sorted by sort_order.",
        "operationId": "getMortgageFileMilestoneChecklist",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "milestone_id",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter by milestone ID"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Offset"
          }
        ],
        "responses": {
          "200": {
            "description": "The checklist items",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/MilestoneChecklistItem"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "description": "Total number of records matching the filter (not just those on the current page)"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/api-service/mortgage-files/{id}/milestones/checklist/{itemId}": {
      "put": {
        "tags": [
          "Milestones"
        ],
        "summary": "Update a checklist item",
        "description": "Partial update: only the fields you send are updated (PUT and PATCH behave identically). If no updatable field is sent, returns 400. You can update label, sort_order, and is_completed. Setting is_completed=true sets completed_at; false clears it.",
        "operationId": "updateMortgageFileMilestoneChecklistItem",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "itemId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The checklist item ID"
          }
        ],
        "requestBody": {
          "description": "The fields to update",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateMilestoneChecklistItem"
              },
              "example": {
                "is_completed": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MilestoneChecklistItem"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "patch": {
        "tags": [
          "Milestones"
        ],
        "summary": "Partially update a checklist item",
        "description": "Partial update: only the fields you send are updated (PUT and PATCH behave identically). If no updatable field is sent, returns 400. You can update label, sort_order, and is_completed. Setting is_completed=true sets completed_at; false clears it.",
        "operationId": "patchMortgageFileMilestoneChecklistItem",
        "parameters": [
          {
            "$ref": "#/components/parameters/MortgageFileId"
          },
          {
            "name": "itemId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "The checklist item ID"
          }
        ],
        "requestBody": {
          "description": "The fields to update",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateMilestoneChecklistItem"
              },
              "example": {
                "is_completed": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated item",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MilestoneChecklistItem"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    }
  },
  "externalDocs": {
    "description": "LLM-friendly docs (llms.txt)",
    "url": "https://docs.banta.co.il/llms.txt"
  },
  "x-tagGroups": [
    {
      "name": "Core resources",
      "tags": [
        "Leads",
        "Customers",
        "Contacts",
        "Mortgage files",
        "Tasks"
      ]
    },
    {
      "name": "Mortgage file",
      "tags": [
        "Borrowers",
        "Timeline",
        "Notes",
        "File contacts",
        "Watchers",
        "Reminders",
        "Milestones",
        "Custom fields"
      ]
    },
    {
      "name": "Documents",
      "tags": [
        "Documents",
        "Document statuses",
        "Signatures",
        "Generated documents"
      ]
    },
    {
      "name": "Billing & analysis",
      "tags": [
        "Charges",
        "Payments",
        "File analysis",
        "Calculator mixes"
      ]
    },
    {
      "name": "System lists",
      "tags": [
        "Lists"
      ]
    }
  ]
}
