{
  "openapi": "3.0.0",
  "info": {
    "title": "HoneyBook API",
    "description": "The HoneyBook API lets you read and write the data behind a HoneyBook account — contacts, projects, workspaces, smart files, tasks, notes, conversations and more.\n\nIt is a JSON HTTP API. Every request is authenticated with an OAuth 2.0 access token, every response is JSON, and every endpoint lives under a single versioned base path.\n\n### Base URL\n\n```\nhttps://api.honeybook.com/api/v3\n```\n\nThe version is part of the path. A new major version gets its own path and its own documentation; endpoints in `v3` are not removed or changed in place.\n\n### Making a request\n\nSend the access token as a bearer token:\n\n```bash\ncurl https://api.honeybook.com/api/v3/contacts \\\n  -H \"Authorization: Bearer <access_token>\"\n```\n\n### How this documentation is organized\n\n**Guides** describe the conventions that apply across the whole API. Read Errors, Pagination and Filtering & Sorting once and they apply to every endpoint you touch.\n\n**API Reference** documents every endpoint, grouped by the resource it belongs to.\n\n### Conventions worth knowing before you start\n\n-   **Identifiers are opaque strings.** An id is a 24-character hexadecimal string. Treat it as an opaque token: do not parse it, and do not assume any structure or ordering.\n-   **Timestamps are ISO 8601** in UTC, for example `2026-08-11T14:30:52Z`. Date-only fields are `YYYY-MM-DD`.\n-   **Money is an object**, not a bare number — an amount together with its currency. Never assume a currency.\n-   **Unknown query parameters are ignored, not rejected.** A misspelled filter name does not produce an error; it simply does not filter. Check your parameter names against the reference when a list returns more rows than you expected.\n-   **Absent is not the same as empty.** A field that was not requested and a field that is genuinely empty are distinguished — see Relation Includes.\n\nThe API is private. To get access, fill in the [Request Access form](#tag/request-access).",
    "version": "v3"
  },
  "tags": [
    {
      "name": "Request Access",
      "description": "The HoneyBook API is currently private. Please submit this form to apply for access.\n\n### How registration works\n\nHoneyBook registers applications itself; there is no self-service sign-up. Once your application is registered you receive a `client_id`, the issuer URL and your granted scopes. **No client secret is ever issued**: your application proves who it is with a key pair instead, as the [Authentication](#tag/authentication) guide explains.\n\nTo register your application, HoneyBook needs:\n\n-   A **JWKS URL** (HTTPS) that publishes your public key.\n-   Your exact **redirect URIs** (HTTPS, no wildcards).\n-   The **scopes** your integration needs, least-privilege.\n-   An **engineering contact** and a **security contact** email.\n\nThe form asks for these in its _Registering your application_ section. If you are approved, HoneyBook uses them to generate your OAuth client.\n\n<div id=\"request-access-form\"></div>"
    },
    {
      "name": "Authentication",
      "description": "The HoneyBook API is authenticated with **OAuth 2.0**, using the authorization code flow with PKCE. Your application never handles a HoneyBook password; the account holder signs in to HoneyBook directly and grants your application a scoped, revocable access token.\n\n### HoneyBook is not the authorization server\n\nThis is the single most important thing to understand before you start, because it determines where your requests go.\n\nHoneyBook operates the **API** and the **sign-in and consent screens**. The OAuth endpoints themselves — `/authorize`, `/token` and token revocation — are served by HoneyBook's identity provider on a **different host**.\n\n| What you are doing                               | Where the request goes                      |\n| ------------------------------------------------ | ------------------------------------------- |\n| Sending the account holder to authorize your app | `https://oauth.honeybook.com/oauth2/auth`   |\n| Exchanging the code for tokens                   | `https://oauth.honeybook.com/oauth2/token`  |\n| Refreshing an access token                       | `https://oauth.honeybook.com/oauth2/token`  |\n| Revoking a token                                 | `https://oauth.honeybook.com/oauth2/revoke` |\n| Calling the API                                  | `https://api.honeybook.com/api/v3/...`      |\n\nThere is no `/token` endpoint under `/api/v3`. Looking for one is the most common wrong turn.\n\n### The flow\n\n1. **Redirect the account holder to the authorization endpoint** with your `client_id`, your registered `redirect_uri`, the scopes you need, `response_type=code`, a `state` value, and a PKCE `code_challenge`.\n2. **The account holder signs in to HoneyBook and reviews what you are asking for.** They see your application's name and a plain-language description of each scope, and they can decline any of them.\n3. **HoneyBook redirects back to your `redirect_uri`** with an authorization code. Verify `state` matches what you sent.\n4. **Exchange the code for tokens** at the token endpoint, sending your `code_verifier` and a `private_key_jwt` client assertion (see _Client authentication_ below — HoneyBook issues no client secret).\n5. **Call the API** with `Authorization: Bearer <access_token>`.\n6. **Refresh** with the refresh token when the access token expires. You only receive a refresh token if you requested the `offline_access` scope.\n\n### Client authentication\n\nTo get a `client_id`, apply through the [Request Access form](#tag/request-access); HoneyBook registers your application and issues no client secret.\n\nHoneyBook authenticates clients with **`private_key_jwt`** (RFC 7523), not a shared secret. You generate a key pair, publish the public key at an HTTPS JWKS URL you host (e.g. `https://your-domain/.well-known/jwks.json`), and prove your identity at the token endpoint by sending a short-lived `client_assertion` JWT signed with your private key. HoneyBook fetches your public key from that URL and verifies the signature — your private key never leaves your infrastructure. Rotating a key is self-serve: publish the new key at the same URL, no coordination needed.\n\nSign the `client_assertion` with **RS256**. ES256 is not accepted.\n\nRedirect URIs must be HTTPS, with no wildcards, and are matched exactly — a trailing slash difference is a mismatch. You may send only one `redirect_uri` parameter per request.\n\nPKCE is required on every authorization request, including for a confidential client like yours.\n\n### Scopes\n\nScopes are granular and follow a `<resource>.<access>` shape: `projects.read`, `contacts.write`, and so on. The API's OAuth 2.0 security scheme lists every scope and what it grants.\n\nThree scopes are required on essentially every integration and are not resource-specific:\n\n| Scope            | What it is for                                                                                                                                            |\n| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `openid`         | Identifies the HoneyBook account that granted access.                                                                                                     |\n| `honeybook.api`  | Permission to call the API at all. Necessary but never sufficient on its own — you still need the resource scope for whatever you are reading or writing. |\n| `offline_access` | Issues a refresh token. Without it, access ends when the access token expires.                                                                            |\n\nAsk only for what you need. The consent screen shows every scope you request, and a long list depresses the rate at which people complete authorization.\n\nWriting implies reading, but not automatically: if you need to both read and write projects, request `projects.read` **and** `projects.write`.\n\n### Which response means what\n\nAuthentication and authorization failures are deliberately not all distinguishable, and one of them will surprise you:\n\n| Response                                                           | Meaning                                                                                       | What to do                                                      |\n| ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |\n| **401** with `WWW-Authenticate: Bearer error=\"invalid_token\"`      | The token is missing, malformed, or expired.                                                  | Refresh the token and retry once.                               |\n| **403** with `WWW-Authenticate: Bearer error=\"insufficient_scope\"` | The token is valid, but was not granted a scope this endpoint requires.                       | Re-authorize with the additional scope. Retrying will not help. |\n| **404**                                                            | Either the record does not exist, **or** it exists and this account is not allowed to see it. | Treat these as the same case.                                   |\n\nThat last row is intentional. The API will not confirm that a record exists to someone who is not entitled to it, so a permission failure is indistinguishable from a genuine miss. Do not write logic that infers existence from a 404."
    },
    {
      "name": "Errors",
      "description": "Every failure returns the same JSON shape, whatever went wrong. You can write one error handler and use it everywhere.\n\n```json\n{\n    \"error\": true,\n    \"is_timeout\": false,\n    \"error_type\": \"HBValidationError\",\n    \"error_message\": \"title is missing\",\n    \"error_data\": {\n        \"fields\": [{ \"field\": \"title\", \"message\": \"is missing\" }]\n    }\n}\n```\n\n| Field           | Notes                                                                                                                              |\n| --------------- | ---------------------------------------------------------------------------------------------------------------------------------- |\n| `error`         | Always `true` on a failure.                                                                                                        |\n| `is_timeout`    | `true` only when the request exceeded the server's time limit. Safe to use as a retry signal.                                      |\n| `error_type`    | A stable machine-readable identifier. Branch on this, never on `error_message`.                                                    |\n| `error_message` | Human-readable. Wording may change at any time.                                                                                    |\n| `error_data`    | Always present, `{}` when there is nothing to add. On a validation failure it carries a `fields` array naming each rejected field. |\n\n### Status codes\n\n| Status  | When                                                                                                                                                              | `error_type`                                                                        |\n| ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |\n| **400** | A parameter or filter failed validation, the request body was malformed, a business rule rejected the request, or the account's plan does not include the feature | `HBValidationError`, `HBBadRequestError`, `HBUserError`, `HBRestrictedFeatureError` |\n| **401** | The access token is missing, malformed or expired                                                                                                                 | `HBInvalidJWTError`                                                                 |\n| **403** | The token is valid but lacks a scope this endpoint requires                                                                                                       | `HBInsufficientScopeError`                                                          |\n| **404** | The record does not exist — **or** it exists and you are not allowed to see it                                                                                    | `HBObjectNotFoundError`, others                                                     |\n| **409** | The request conflicts with the current state, such as a duplicate or an illegal status transition                                                                 | `HBConflictError`                                                                   |\n| **410** | The record existed and has been deleted                                                                                                                           | `HBObjectDeletedError`                                                              |\n| **500** | Something went wrong on our side                                                                                                                                  | `HBInternalError`                                                                   |\n| **503** | The endpoint is temporarily shedding load                                                                                                                         | `HBTempSuspendedRouteError`                                                         |\n\n### Two behaviours that catch people out\n\n**A permission failure returns 404, not 403.** If your token is valid but the record belongs to another account, you get a 404 that is byte-for-byte identical to the one you would get for an id that never existed. This is deliberate: the API will not confirm a record exists to someone not entitled to see it. The single exception is a missing OAuth scope, which returns 403 — there, the caller is known and the requirement is public.\n\n**A 500 never names the underlying failure.** `error_type` is normalized to `HBInternalError` and the message is generic. If you need us to investigate one, capture the request path, the time, and any correlation headers on the response.\n\n### Retrying\n\nRetry on **500**, **503**, and any response where `is_timeout` is `true`, with exponential backoff. Do not retry **400**, **401**, **403**, **404**, **409** or **410** — the same request will fail the same way. The one exception is a `409` with `error_type` `HBIdempotencyKeyInFlight`, which is safe to retry; see [Idempotency](#tag/idempotency). A **401** is worth exactly one retry, after refreshing the token."
    },
    {
      "name": "Idempotency",
      "description": "Send an `Idempotency-Key` header on a `POST` to retry it safely. If a network failure or timeout leaves you unsure whether a create succeeded, resend the same request with the same key: you get the original response, not a duplicate record.\n\nThe header is optional and accepted on every `POST`. A request without it behaves normally.\n\n### Using a key\n\n```\nPOST /api/v3/projects\nIdempotency-Key: 4f0c2a52-8d1e-4b8a-9d57-0a6f1c9e7b21\n```\n\n-   Use a unique value per logical operation, such as a UUID v4. 1-255 printable ASCII characters.\n-   On retry, send the **same key, path and body**.\n-   Keys are scoped to your application and the authorizing user, so they never collide with another integration's.\n\n### What a retry returns\n\nWithin **24 hours** of the first request, a repeat with the same key returns the first response verbatim: same status, same body, plus the header `Idempotent-Replayed: true`.\n\nThe replay is a stored copy. Later edits to the record, and a different `include` parameter, are not reflected in it.\n\n### Errors\n\n| Status  | `error_type`               | Meaning                                                  | What to do                               |\n| ------- | -------------------------- | -------------------------------------------------------- | ---------------------------------------- |\n| **400** | `HBIdempotencyKeyInvalid`  | Key is not 1-255 printable ASCII.                        | Fix the key.                             |\n| **409** | `HBIdempotencyKeyInFlight` | The first request with this key is still running.        | Retry after a short backoff, same key.   |\n| **422** | `HBIdempotencyKeyReused`   | The key was already used with a different path or body.  | Use a new key for a different operation. |\n| **503** | `HBIdempotencyUnavailable` | Idempotency could not be checked. Nothing was processed. | Retry with backoff, same key.            |\n\nUnlike other `409` responses, `HBIdempotencyKeyInFlight` is safe to retry. See [Errors](#tag/errors)."
    },
    {
      "name": "Pagination",
      "description": "Every endpoint that returns a list is paginated, and they all use the same two parameters and the same envelope.\n\n### Parameters\n\n| Parameter  | Default | Limit                               |\n| ---------- | ------- | ----------------------------------- |\n| `page`     | `1`     | Pages are 1-indexed, not 0-indexed. |\n| `per_page` | `25`    | Maximum **100**.                    |\n\n```\nGET /api/v3/contacts?page=2&per_page=50\n```\n\n### The envelope\n\nA paginated response is always an object with `data` and `pagination`. It is never a bare array, so the response shape does not change when there are no results.\n\n```json\n{\n    \"data\": [{ \"id\": \"6512a0b3f8d4c21a9e7b3f01\", \"name\": \"Ada Lovelace\" }],\n    \"pagination\": {\n        \"page\": 1,\n        \"per_page\": 25,\n        \"total_items\": 100,\n        \"total_pages\": 4,\n        \"last_page\": false,\n        \"offset\": 0\n    }\n}\n```\n\n| Field              | Meaning                                                              |\n| ------------------ | -------------------------------------------------------------------- |\n| `page`, `per_page` | Echo of what was applied, after defaults and clamping.               |\n| `total_items`      | Total matching the query across all pages, not the number in `data`. |\n| `total_pages`      | Total pages at the current `per_page`.                               |\n| `last_page`        | `true` on the final page. Use this to end your loop.                 |\n| `offset`           | Index of the first row in `data` within the full result set.         |\n\n### Iterating a full list\n\nLoop until `pagination.last_page` is `true`. Do not stop when `data` is shorter than `per_page` — that is also true of the last page, but checking the flag is unambiguous.\n\n```\npage = 1\nloop:\n  response = GET /api/v3/contacts?page=<page>&per_page=100\n  process(response.data)\n  if response.pagination.last_page: stop\n  page = page + 1\n```\n\nPrefer a larger `per_page` over more requests. Fetching 1,000 records at `per_page=100` is ten requests; at the default it is forty.\n\n### Deep pagination has a limit\n\nSome list endpoints are backed by a search index that cannot page arbitrarily deep. Past roughly 10,000 records, they return **400** rather than failing partway through. If you need to walk a very large collection, narrow it with filters — by date range, by status, by owner — rather than paging further into an unfiltered list.\n\n### Results can shift between pages\n\nPagination is a snapshot per request, not per traversal. If records are created or deleted while you are iterating, a record can appear on two pages or on none. When exactness matters, sort by a stable field such as `created_at` and filter to a closed time range so the underlying set cannot change beneath you."
    },
    {
      "name": "Filtering & Sorting",
      "description": "List endpoints are narrowed with flat, named query parameters. There is no query language and no operator syntax — each parameter has one fixed meaning, documented on the endpoint.\n\n```\nGET /api/v3/tasks\n  ?status=open\n  &due_after=2026-01-01\n  &due_before=2026-06-30\n  &assignee_ids=6512a0b3f8d4c21a9e7b3f01,6512a0b3f8d4c21a9e7b3f02\n  &sort=-due_date,title\n  &page=1&per_page=25\n```\n\n### How filters are named\n\nThe name tells you the comparison. You never write one.\n\n| Shape                              | Meaning               | Example                    |\n| ---------------------------------- | --------------------- | -------------------------- |\n| `<field>`                          | Equals                | `status=open`              |\n| `<field>_after` / `<field>_before` | Inclusive range bound | `due_after=2026-01-01`     |\n| `<field>_ids`                      | Matches any of a set  | `assignee_ids=<id1>,<id2>` |\n\nA range is expressed as two separate parameters targeting the same field. Send `due_after` alone for an open-ended lower bound, `due_before` alone for an upper bound, or both for a closed range.\n\n### Multiple values\n\nA set parameter takes either a comma-separated list or the same key repeated. These are equivalent:\n\n```\n?assignee_ids=<id1>,<id2>\n?assignee_ids=<id1>&assignee_ids=<id2>\n```\n\nSome set parameters also accept the literal token `none`, which matches records where the field is unset. Where it is supported, the endpoint's parameter description says so.\n\n```\n?workspace_ids=<id>,none\n```\n\nDifferent filters combine with AND. Values within one set parameter combine with OR.\n\n### Sorting\n\n```\n?sort=-due_date,title\n```\n\nComma-separated fields, applied in order as tie-breakers. A `-` prefix sorts descending; no prefix sorts ascending. Each endpoint documents which fields are sortable and what its default sort is.\n\n### Two behaviours to be aware of\n\n**An unrecognized parameter is ignored, not rejected.** `?stauts=open` returns unfiltered results with a 200, not a 400. This is standard for flat-parameter REST APIs, but it means a typo shows up as too many rows rather than as an error. When a list looks too broad, check your parameter spelling first.\n\n**A recognized parameter with an unusable value is a 400.** `?due_after=not-a-date` fails immediately rather than being silently dropped.\n\n**Enumerated filters list their allowed values** in the reference. Sending a value outside the list is not guaranteed to be rejected — depending on the field it may simply match nothing — so use the documented values."
    },
    {
      "name": "Relation Includes",
      "description": "Responses reference related records by id rather than embedding them. When you need the referenced record itself, ask for it by name with `include` instead of making a second request per row.\n\n```\nGET /api/v3/contacts?include=user,workspaces&max_workspaces=5\n```\n\nNothing is populated unless you ask. This keeps the common case fast and makes the cost of a fat response something you opt into.\n\n### The field is always there\n\nAn includable field is present in every response. Its **value** tells you what happened, so you never have to check whether a key exists.\n\n|                               | Not requested | Requested, none exist              | Requested and found                   |\n| ----------------------------- | ------------- | ---------------------------------- | ------------------------------------- |\n| Single relation, e.g. `user`  | `null`        | `null`                             | `{ ... }`                             |\n| Collection, e.g. `workspaces` | `null`        | `{ \"data\": [], \"total_items\": 0 }` | `{ \"data\": [...], \"total_items\": 7 }` |\n\nAn included collection is an object, not a bare array:\n\n```json\n{\n    \"id\": \"6512a0b3f8d4c21a9e7b3f01\",\n    \"name\": \"Ada Lovelace\",\n    \"user\": { \"id\": \"...\", \"first_name\": \"Ada\" },\n    \"workspaces\": {\n        \"data\": [{ \"id\": \"...\", \"name\": \"Spring wedding\" }],\n        \"total_items\": 7\n    }\n}\n```\n\n### `total_items` is how you detect truncation\n\n`total_items` is the true number of related records for that specific parent — not the number returned. When `total_items` is larger than `data.length`, you hit your own limit and there are more. Fetch the rest from the related resource's own endpoint.\n\n### Limiting a collection\n\nEach includable collection has a `max_<name>` parameter, defaulting to **3**, with a maximum of **25**.\n\n```\n?include=workspaces&max_workspaces=10\n```\n\nThe limit is per parent record, so it multiplies with `per_page`. `per_page=100&max_workspaces=25` asks for up to 2,500 nested records in one response — usually a sign you want the related endpoint directly instead.\n\nA value outside the allowed range is a **400**, never a silent clamp.\n\n### Rules\n\n-   **Only one level.** `include=workspaces.project` is a **400**. To go deeper, make a second request against the related resource.\n-   **`max_*` requires its `include`.** Sending `max_workspaces` without `include=workspaces` is a **400**, not a silently ignored parameter.\n-   **Unknown include names are a 400.** Unlike filters, includes are validated — a typo here fails loudly.\n-   **Each endpoint documents what it supports.** The set of includable relations differs per resource and is listed on the endpoint."
    },
    {
      "name": "Async Operations",
      "description": "Almost every endpoint completes within the request. A small number of operations do real work in the background — generating a document, calling a payment provider, processing an unbounded collection — and those return immediately with a task you poll.\n\nYou can tell them apart from the reference: an asynchronous operation is documented as returning **202 Accepted**.\n\n### The pattern\n\n**1. Start the work.** The operation returns `202` with a task:\n\n```json\n{\n    \"id\": \"6512a0b3f8d4c21a9e7b3f09\",\n    \"task_type\": \"create_pay_link\",\n    \"status\": \"pending\",\n    \"result_resource_type\": null,\n    \"result_resource_id\": null,\n    \"failure_reason\": null,\n    \"created_at\": \"2026-08-11T14:30:52Z\",\n    \"updated_at\": \"2026-08-11T14:30:52Z\"\n}\n```\n\n**2. Poll for completion** at the single shared status endpoint, using the task's `id`:\n\n```\nGET /api/v3/async_tasks/6512a0b3f8d4c21a9e7b3f09\n```\n\nEvery asynchronous operation in the API polls the same endpoint. There is one to implement, not one per feature.\n\n**3. Fetch the result.** On success the task carries a **pointer**, not the result itself:\n\n```json\n{\n    \"status\": \"succeeded\",\n    \"result_resource_type\": \"pay_link\",\n    \"result_resource_id\": \"6512a0b3f8d4c21a9e7b3f10\"\n}\n```\n\nRead the finished record from that resource's own endpoint — here, `GET /api/v3/pay_links/6512a0b3f8d4c21a9e7b3f10`. The task never carries the result inline and never carries a URL, so the result is always fetched through a documented, typed endpoint you already know how to read.\n\n### Status values\n\n| `status`    | Meaning                                                        |\n| ----------- | -------------------------------------------------------------- |\n| `pending`   | Still running. Keep polling.                                   |\n| `succeeded` | Done. `result_resource_type` and `result_resource_id` are set. |\n| `failed`    | Terminal. `failure_reason` explains why. Do not keep polling.  |\n\n`pending` means background work in flight and nothing else. A business state that merely sounds pending — awaiting payment, awaiting approval — is a different field with its own specific value.\n\n### Polling advice\n\nPoll with a short initial delay and back off — roughly one second, then two, then four, capping around thirty. Do not poll in a tight loop.\n\n**Tasks do not live forever.** They are retained for a limited period after their last update and then removed. Polling a task past its retention returns **404**, so treat a 404 on a task you have not seen complete as an inconclusive result, not as a failure — check the target resource before retrying the operation.\n\n**No result is delivered to you.** There are no webhooks or callbacks for task completion, and there is no `Location` header on the `202`. Polling is the only mechanism."
    },
    {
      "name": "Contacts",
      "description": "Operations about Contacts"
    },
    {
      "name": "CustomFields",
      "description": "Operations about CustomFields"
    },
    {
      "name": "Inquiries",
      "description": "Operations about Inquiries"
    },
    {
      "name": "Pipeline",
      "description": "Operations about Pipelines"
    },
    {
      "name": "Workspaces",
      "description": "Operations about Workspaces"
    },
    {
      "name": "LeadSources",
      "description": "Operations about LeadSources"
    },
    {
      "name": "Projects",
      "description": "Operations about Projects"
    }
  ],
  "paths": {
    "/contacts": {
      "post": {
        "summary": "Create a contact",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "description": "Optional, 1-255 printable ASCII. Retrying with the same key, path and body within 24h returns the first response verbatim (`Idempotent-Replayed: true`) instead of creating another. See the [Idempotency guide](#tag/idempotency).",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/createContact"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Create a contact",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_Contact"
                }
              }
            }
          }
        },
        "tags": [
          "Contacts"
        ],
        "operationId": "createContact",
        "x-hb-resource": "contacts",
        "security": [
          {
            "oauth2": [
              "contacts.write"
            ]
          },
          {
            "oauth2": [
              "contacts.write_own"
            ]
          }
        ]
      }
    },
    "/contacts/{id}": {
      "patch": {
        "summary": "Update a contact (partial; data fields only)",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Contact id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/updateContact"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Update a contact (partial; data fields only)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_Contact"
                }
              }
            }
          }
        },
        "tags": [
          "Contacts"
        ],
        "operationId": "updateContact",
        "x-hb-resource": "contacts",
        "security": [
          {
            "oauth2": [
              "contacts.write"
            ]
          },
          {
            "oauth2": [
              "contacts.write_own"
            ]
          }
        ]
      },
      "delete": {
        "summary": "Delete a contact",
        "description": "Deletes the contact. An optional `reaction_text` — the reason the member typed while deleting — is recorded as a dislike Reaction on the contact when the contact came from an AI lead suggestion, and ignored otherwise.",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Contact id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/deleteContact"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "Delete a contact"
          }
        },
        "tags": [
          "Contacts"
        ],
        "operationId": "deleteContact",
        "x-hb-risk": {
          "level": "dangerous",
          "reason": "Permanently deletes the contact."
        },
        "x-hb-resource": "contacts",
        "security": [
          {
            "oauth2": [
              "contacts.write"
            ]
          },
          {
            "oauth2": [
              "contacts.write_own"
            ]
          }
        ]
      }
    },
    "/contacts/{id}/interaction": {
      "put": {
        "summary": "Set (replace) a contact's last interaction",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Contact id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/updateContactInteraction"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Set (replace) a contact's last interaction",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_Contact"
                }
              }
            }
          }
        },
        "tags": [
          "Contacts"
        ],
        "operationId": "updateContactInteraction",
        "x-hb-resource": "contacts",
        "security": [
          {
            "oauth2": [
              "contacts.write"
            ]
          },
          {
            "oauth2": [
              "contacts.write_own"
            ]
          }
        ]
      }
    },
    "/contacts/{id}/tags/{tag_id}": {
      "put": {
        "summary": "Tag a contact (idempotent)",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Contact id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "tag_id",
            "description": "Tag id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/addContactTag"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Tag a contact (idempotent)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_Contact"
                }
              }
            }
          }
        },
        "tags": [
          "Contacts"
        ],
        "operationId": "addContactTag",
        "x-hb-resource": "contacts",
        "security": [
          {
            "oauth2": [
              "contacts.write"
            ]
          },
          {
            "oauth2": [
              "contacts.write_own"
            ]
          }
        ]
      },
      "delete": {
        "summary": "Untag a contact (idempotent)",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Contact id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "tag_id",
            "description": "Tag id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Untag a contact (idempotent)"
          }
        },
        "tags": [
          "Contacts"
        ],
        "operationId": "removeContactTag",
        "x-hb-resource": "contacts",
        "security": [
          {
            "oauth2": [
              "contacts.write"
            ]
          },
          {
            "oauth2": [
              "contacts.write_own"
            ]
          }
        ]
      }
    },
    "/contacts/{id}/custom_fields": {
      "get": {
        "summary": "List a contact's custom field values",
        "description": "One row per LIVE custom field the company defines for contacts, whether or not this contact has a value for it — `value` is null (or `[]` for multi_select) when unset, which is how a caller learns the field exists and is empty. Narrow on `type` to read `value`: a String for text/long_text/link, a number for number, an ISO8601 date for date, and the selected option object(s) for the selects. Same rows as `?include=custom_fields`; one default page holds them all.",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Contact id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "in": "query",
            "name": "page",
            "description": "1-indexed page number",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 1,
              "maximum": 1000000,
              "default": 1
            }
          },
          {
            "in": "query",
            "name": "per_page",
            "description": "Page size (max 500)",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 1,
              "maximum": 500,
              "default": 500
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List a contact's custom field values",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_CustomFieldValue_Page"
                }
              }
            }
          }
        },
        "tags": [
          "Contacts",
          "CustomFields"
        ],
        "operationId": "listContactCustomFields",
        "x-hb-resource": "contacts",
        "security": [
          {
            "oauth2": [
              "contacts.read"
            ]
          },
          {
            "oauth2": [
              "contacts.read_own"
            ]
          }
        ]
      }
    },
    "/contacts/{id}/custom_fields/{field_id}": {
      "patch": {
        "summary": "Set a contact's value for one custom field",
        "description": "The field id in the path already fixes the type, so `value` is sent as a String for every kind and coerced server-side: a number as its digits (\"42\"), a date as ISO8601 (\"2026-09-15\"), a single_select as the chosen option's id, a multi_select as a comma-separated list of option ids. A value the field's type rejects is a 400. Returns the field's node, so the caller sees the stored, coerced result.",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Contact id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "field_id",
            "description": "Custom field id (the `id` of a GET /custom_fields row)",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/updateContactCustomField"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Set a contact's value for one custom field",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_CustomFieldValue"
                }
              }
            }
          }
        },
        "tags": [
          "Contacts",
          "CustomFields"
        ],
        "operationId": "updateContactCustomField",
        "x-hb-resource": "contacts",
        "security": [
          {
            "oauth2": [
              "contacts.write"
            ]
          },
          {
            "oauth2": [
              "contacts.write_own"
            ]
          }
        ]
      },
      "delete": {
        "summary": "Clear a contact's value for one custom field",
        "description": "The field itself is untouched — it stays on every contact, including this one, with no value. Deleting the FIELD is DELETE /custom_fields/:id.",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Contact id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "field_id",
            "description": "Custom field id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Clear a contact's value for one custom field"
          }
        },
        "tags": [
          "Contacts",
          "CustomFields"
        ],
        "operationId": "clearContactCustomField",
        "x-hb-resource": "contacts",
        "security": [
          {
            "oauth2": [
              "contacts.write"
            ]
          },
          {
            "oauth2": [
              "contacts.write_own"
            ]
          }
        ]
      }
    },
    "/custom_fields": {
      "get": {
        "summary": "List the caller company's custom field definitions",
        "description": "The field definitions themselves. To read or write what one PROJECT or CONTACT holds for a field, use /projects/:id/custom_fields or /contacts/:id/custom_fields — the `id` of a row here is the `field_id` there.",
        "parameters": [
          {
            "in": "query",
            "name": "entity_type",
            "description": "Which kind of record the field appears on. One of: project, contact",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "project",
                "contact"
              ]
            }
          },
          {
            "in": "query",
            "name": "archived",
            "description": "Restrict to the fields the member has deleted (true) or still uses (false). Omitted, only live fields are returned",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "in": "query",
            "name": "page",
            "description": "1-indexed page number",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 1,
              "maximum": 1000000,
              "default": 1
            }
          },
          {
            "in": "query",
            "name": "per_page",
            "description": "Page size (max 100)",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "in": "query",
            "name": "name_contains",
            "description": "name contains (case-insensitive)",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "type",
            "description": "type =",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "text",
                "long_text",
                "date",
                "number",
                "link",
                "single_select",
                "multi_select"
              ]
            }
          },
          {
            "in": "query",
            "name": "created_after",
            "description": "created_at >=",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "in": "query",
            "name": "created_before",
            "description": "created_at <=",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "in": "query",
            "name": "sort",
            "description": "Comma-separated sort keys; '-' prefix = descending. Allowed: order, name, created_at, updated_at. Default: order.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List the caller company's custom field definitions",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_CustomField_Page"
                }
              }
            }
          }
        },
        "tags": [
          "CustomFields"
        ],
        "operationId": "listCustomFields",
        "x-hb-resource": "custom_fields",
        "security": [
          {
            "oauth2": [
              "account.read"
            ]
          }
        ]
      },
      "post": {
        "summary": "Create a custom field definition",
        "description": "Requires company admin. The field appears on every record of `entity_type` from now on, empty until a value is set on each.",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "description": "Optional, 1-255 printable ASCII. Retrying with the same key, path and body within 24h returns the first response verbatim (`Idempotent-Replayed: true`) instead of creating another. See the [Idempotency guide](#tag/idempotency).",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/createCustomField"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Create a custom field definition",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_CustomField"
                }
              }
            }
          }
        },
        "tags": [
          "CustomFields"
        ],
        "operationId": "createCustomField",
        "x-hb-resource": "custom_fields",
        "security": [
          {
            "oauth2": [
              "account.write"
            ]
          }
        ]
      }
    },
    "/custom_fields/{id}": {
      "get": {
        "summary": "Get a custom field definition by id",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Custom field id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Get a custom field definition by id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_CustomField"
                }
              }
            }
          }
        },
        "tags": [
          "CustomFields"
        ],
        "operationId": "getCustomField",
        "x-hb-resource": "custom_fields",
        "security": [
          {
            "oauth2": [
              "account.read"
            ]
          }
        ]
      },
      "patch": {
        "summary": "Update a custom field definition (partial)",
        "description": "Requires company admin. `entity_type` and `type` are NOT changeable — a field that changed kind would strand every value already stored against it; create a new field instead. `options`, when sent, REPLACES the whole list: carry an existing option's `id` to keep it and the selections pointing at it.",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Custom field id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/updateCustomField"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Update a custom field definition (partial)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_CustomField"
                }
              }
            }
          }
        },
        "tags": [
          "CustomFields"
        ],
        "operationId": "updateCustomField",
        "x-hb-resource": "custom_fields",
        "security": [
          {
            "oauth2": [
              "account.write"
            ]
          }
        ]
      },
      "delete": {
        "summary": "Delete a custom field definition",
        "description": "Requires company admin. Archives the field rather than destroying it: it stops appearing on records without a value for it, and it cannot be updated, but values are retained. Undo with POST /custom_fields/:id/restore.",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Custom field id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Delete a custom field definition"
          }
        },
        "tags": [
          "CustomFields"
        ],
        "operationId": "deleteCustomField",
        "x-hb-resource": "custom_fields",
        "security": [
          {
            "oauth2": [
              "account.write"
            ]
          }
        ]
      }
    },
    "/custom_fields/{id}/restore": {
      "post": {
        "summary": "Restore an archived custom field definition",
        "description": "Requires company admin. Un-archives the field with its values. Re-checks the per-entity limit (400) and name uniqueness (422); 409 when the field is not archived.",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "description": "Optional, 1-255 printable ASCII. Retrying with the same key, path and body within 24h returns the first response verbatim (`Idempotent-Replayed: true`) instead of creating another. See the [Idempotency guide](#tag/idempotency).",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "id",
            "description": "Custom field id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Restore an archived custom field definition",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_CustomField"
                }
              }
            }
          }
        },
        "tags": [
          "CustomFields"
        ],
        "operationId": "restoreCustomField",
        "x-hb-resource": "custom_fields",
        "security": [
          {
            "oauth2": [
              "account.write"
            ]
          }
        ]
      }
    },
    "/inquiries": {
      "get": {
        "summary": "List the calling company's inquiries",
        "parameters": [
          {
            "in": "query",
            "name": "page",
            "description": "1-indexed page number",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 1,
              "maximum": 1000000,
              "default": 1
            }
          },
          {
            "in": "query",
            "name": "per_page",
            "description": "Page size (max 100)",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "in": "query",
            "name": "include",
            "description": "Comma-separated relations to populate. Allowed: contact. A relation not requested is null. Nested paths (a.b) are not supported.",
            "required": false,
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "contact"
                ]
              }
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "in": "query",
            "name": "contact_ids",
            "description": "Restrict to inquiries of these contacts (comma-separated contact ids)",
            "required": false,
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "in": "query",
            "name": "status",
            "description": "Restrict to inquiries in this processing status",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "processed",
                "dropped"
              ]
            }
          },
          {
            "in": "query",
            "name": "project_ids",
            "description": "project_id in (comma-separated)",
            "required": false,
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "in": "query",
            "name": "source",
            "description": "Restrict to inquiries created through this surface",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "contact_form",
                "lead_form",
                "scheduler",
                "api",
                "unknown"
              ]
            }
          },
          {
            "in": "query",
            "name": "created_after",
            "description": "created_at >=",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "in": "query",
            "name": "created_before",
            "description": "created_at <=",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "in": "query",
            "name": "sort",
            "description": "Comma-separated sort keys; '-' prefix = descending. Allowed: created_at. Default: -created_at.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List the calling company's inquiries",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_Inquiry_Page"
                }
              }
            }
          }
        },
        "tags": [
          "Inquiries"
        ],
        "operationId": "listInquiries",
        "x-hb-resource": "inquiries",
        "security": [
          {
            "oauth2": [
              "projects.read"
            ]
          },
          {
            "oauth2": [
              "projects.read_own"
            ]
          }
        ]
      },
      "post": {
        "summary": "Submit an inquiry",
        "description": "Persists the inquiry as `pending` and returns 202 + an AsyncTask. The project, contact and notifications are built in the background; poll GET /api/v3/async_tasks/:id and, on success, fetch the inquiry via result_resource_id. A contact matched by email is reused and never overwritten. An unknown lead_source_id or project_type_id is a 404. `contact.custom_fields` and `project.custom_fields` are validated before the 202 (unknown, foreign, archived or wrong-kind field is a 404; an invalid value or repeated field_id is a 400) but written only to a newly created contact / project: for a matched contact or a reused project the values are skipped, with no signal in the 202. Inquiries submitted this way do not start automations.",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "description": "Optional, 1-255 printable ASCII. Retrying with the same key, path and body within 24h returns the first response verbatim (`Idempotent-Replayed: true`) instead of creating another. See the [Idempotency guide](#tag/idempotency).",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/createInquiry"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "description": "Submit an inquiry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_AsyncTask"
                }
              }
            }
          }
        },
        "tags": [
          "Inquiries"
        ],
        "operationId": "createInquiry",
        "x-hb-risk": {
          "level": "dangerous",
          "reason": "Emails the submitter an out-of-office reply, notifies the company's members, and creates a project and contact."
        },
        "x-hb-resource": "inquiries",
        "security": [
          {
            "oauth2": [
              "projects.write"
            ]
          },
          {
            "oauth2": [
              "projects.write_own"
            ]
          }
        ]
      }
    },
    "/inquiries/{id}": {
      "get": {
        "summary": "Get an inquiry by id",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Inquiry id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "include",
            "description": "Comma-separated relations to populate. Allowed: contact. A relation not requested is null. Nested paths (a.b) are not supported.",
            "required": false,
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "contact"
                ]
              }
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Get an inquiry by id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_Inquiry"
                }
              }
            }
          }
        },
        "tags": [
          "Inquiries"
        ],
        "operationId": "getInquiry",
        "x-hb-resource": "inquiries",
        "security": [
          {
            "oauth2": [
              "projects.read"
            ]
          },
          {
            "oauth2": [
              "projects.read_own"
            ]
          }
        ]
      }
    },
    "/pipeline": {
      "get": {
        "summary": "List the caller company's pipeline (workspaces by stage)",
        "description": "Company-scoped, narrowed to team members' pipelines. Defaults to the caller's own pipeline: only workspaces the caller is a member of. Pass `user_ids` to view other team members' pipelines, or every member's to see the whole company (moderator+). Sorted by `stage_moved_at` descending unless `sort` says otherwise.",
        "parameters": [
          {
            "in": "query",
            "name": "user_ids",
            "description": "Team-member user ids whose pipeline to show. Default: the caller only. Viewing other users requires moderator+ and team membership.",
            "required": false,
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "in": "query",
            "name": "page",
            "description": "1-indexed page number",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 1,
              "maximum": 1000000,
              "default": 1
            }
          },
          {
            "in": "query",
            "name": "per_page",
            "description": "Page size (max 100)",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "in": "query",
            "name": "stage_ids",
            "description": "Pipeline stage ids to include (comma-separated)",
            "required": false,
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "in": "query",
            "name": "view_id",
            "description": "Custom view id; resolves to the view's stage scope (overridden by stage_ids)",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "group",
            "description": "Stage group. Default: none (all groups). `projects` also includes stages with no group",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "opportunities",
                "projects"
              ]
            }
          },
          {
            "in": "query",
            "name": "category",
            "description": "Stage category",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "lead",
                "booked",
                "other"
              ]
            }
          },
          {
            "in": "query",
            "name": "tag_ids",
            "description": "Workspace tag ids (comma-separated)",
            "required": false,
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "in": "query",
            "name": "project_type_ids",
            "description": "Project-type ids (comma-separated)",
            "required": false,
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "in": "query",
            "name": "lead_source_ids",
            "description": "Lead-source ids (comma-separated)",
            "required": false,
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "in": "query",
            "name": "archived",
            "description": "Return archived workspaces instead of active ones. Default: false (active only)",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "in": "query",
            "name": "untracked",
            "description": "Include tracking-disabled (untracked) workspaces. Default: false (excluded)",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "in": "query",
            "name": "has_suggestion",
            "description": "Restrict to workspaces that do (true) or do not (false) have a live follow-up suggestion. Ignored when the caller has follow-up suggestions disabled",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "in": "query",
            "name": "sort",
            "description": "Sort key; '-' prefix = descending. A single key only. Allowed: stage_moved_at, project_date, name, last_activity_at, created_at, stage, project_type, lead_source. Default: -stage_moved_at.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List the caller company's pipeline (workspaces by stage)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_PipelineEntry_Page"
                }
              }
            }
          }
        },
        "tags": [
          "Pipeline"
        ],
        "operationId": "listPipeline",
        "x-hb-resource": "pipeline",
        "security": [
          {
            "oauth2": [
              "workspaces.read"
            ]
          }
        ]
      }
    },
    "/pipeline/counts": {
      "get": {
        "summary": "Pipeline stage/category tallies for the caller's company",
        "description": "Active/archived/untracked totals, per-category tallies, and per-stage counts over the same population as listPipeline: the caller's own pipeline unless `user_ids` is given. Custom views are NOT included (see GET /custom_views).",
        "parameters": [
          {
            "in": "query",
            "name": "user_ids",
            "description": "Team-member user ids whose pipeline to tally. Default: the caller only. Tallying other users requires moderator+ and team membership.",
            "required": false,
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "in": "query",
            "name": "view_id",
            "description": "Custom view id; resolves to the view's stage scope (overridden by stage_ids)",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "group",
            "description": "Stage group. Default: none (all groups). `projects` also includes stages with no group",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "opportunities",
                "projects"
              ]
            }
          },
          {
            "in": "query",
            "name": "category",
            "description": "Stage category",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "lead",
                "booked",
                "other"
              ]
            }
          },
          {
            "in": "query",
            "name": "tag_ids",
            "description": "Workspace tag ids (comma-separated)",
            "required": false,
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "in": "query",
            "name": "project_type_ids",
            "description": "Project-type ids (comma-separated)",
            "required": false,
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "in": "query",
            "name": "lead_source_ids",
            "description": "Lead-source ids (comma-separated)",
            "required": false,
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "in": "query",
            "name": "has_suggestion",
            "description": "Restrict to workspaces that do (true) or do not (false) have a live follow-up suggestion. Ignored when the caller has follow-up suggestions disabled",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Pipeline stage/category tallies for the caller's company",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_PipelineCounts"
                }
              }
            }
          }
        },
        "tags": [
          "Pipeline"
        ],
        "operationId": "getPipelineCounts",
        "x-hb-resource": "pipeline",
        "security": [
          {
            "oauth2": [
              "workspaces.read"
            ]
          }
        ]
      }
    },
    "/workspaces": {
      "get": {
        "summary": "List the workspaces the caller can read",
        "description": "A moderator or greater reads every workspace their company owns plus those they are a member of; any other member reads only the workspaces they are a member of. `member_ids` narrows that set and never widens it: for a member below moderator it can only name themselves, any other id matches nothing. The counts and existence reads (getWorkspaceCounts, hasAnyWorkspace) share this exact population, so getWorkspaceCounts.all == this list's total_items.",
        "parameters": [
          {
            "in": "query",
            "name": "page",
            "description": "1-indexed page number",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 1,
              "maximum": 1000000,
              "default": 1
            }
          },
          {
            "in": "query",
            "name": "per_page",
            "description": "Page size (max 100)",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "in": "query",
            "name": "member_ids",
            "description": "Narrow to rows these members belong to (comma-separated user ids). A caller below moderator can only narrow to themselves; other ids match nothing",
            "required": false,
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "in": "query",
            "name": "project_id",
            "description": "event_id =",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "status",
            "description": "workspace_status =",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "lead",
                "lead_archived",
                "client",
                "client_archived",
                "lead_sent"
              ]
            }
          },
          {
            "in": "query",
            "name": "kind",
            "description": "workspace_type =",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "general",
                "team",
                "design",
                "all_vendors",
                "timeline"
              ]
            }
          },
          {
            "in": "query",
            "name": "archived",
            "description": "is_archived =",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "in": "query",
            "name": "created_after",
            "description": "created_at >=",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "in": "query",
            "name": "created_before",
            "description": "created_at <=",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "in": "query",
            "name": "sort",
            "description": "Comma-separated sort keys; '-' prefix = descending. Allowed: created_at, updated_at. Default: -created_at.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List the workspaces the caller can read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_Workspace_Page"
                }
              }
            }
          }
        },
        "tags": [
          "Workspaces"
        ],
        "operationId": "listWorkspaces",
        "x-hb-resource": "workspaces",
        "security": [
          {
            "oauth2": [
              "workspaces.read"
            ]
          },
          {
            "oauth2": [
              "workspaces.read_own"
            ]
          }
        ]
      }
    },
    "/workspaces/counts": {
      "get": {
        "summary": "Workspace counts over the workspaces the caller can read (all / active / inactive)",
        "description": "Over the SAME population as listWorkspaces, decomposed along the list's `archived` filter: active = not archived, inactive = archived, all = active + inactive. So all == listWorkspaces total_items and inactive == listWorkspaces?archived=true.",
        "parameters": [
          {
            "in": "query",
            "name": "member_ids",
            "description": "Narrow to rows these members belong to (comma-separated user ids). A caller below moderator can only narrow to themselves; other ids match nothing",
            "required": false,
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Workspace counts over the workspaces the caller can read (all / active / inactive)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_WorkspaceCounts"
                }
              }
            }
          }
        },
        "tags": [
          "Workspaces"
        ],
        "operationId": "getWorkspaceCounts",
        "x-hb-resource": "workspaces",
        "security": [
          {
            "oauth2": [
              "workspaces.read"
            ]
          }
        ]
      }
    },
    "/workspaces/any": {
      "get": {
        "summary": "Whether the caller can read any workspace",
        "description": "Existence over the SAME population as listWorkspaces: true iff that list is not empty (equivalently, getWorkspaceCounts.all > 0).",
        "parameters": [
          {
            "in": "query",
            "name": "member_ids",
            "description": "Narrow to rows these members belong to (comma-separated user ids). A caller below moderator can only narrow to themselves; other ids match nothing",
            "required": false,
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Whether the caller can read any workspace",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_WorkspaceExistence"
                }
              }
            }
          }
        },
        "tags": [
          "Workspaces"
        ],
        "operationId": "hasAnyWorkspace",
        "x-hb-resource": "workspaces",
        "security": [
          {
            "oauth2": [
              "workspaces.read"
            ]
          }
        ]
      }
    },
    "/workspaces/{id}": {
      "get": {
        "summary": "Get a workspace by id",
        "description": "Only a workspace member, or a moderator-or-greater of the workspace's company, may read it; anyone else gets a 404. A workspace that existed and was deleted answers 410 (HBWorkspaceDeletedError) rather than 404, so a client can tell \"gone\" from \"never yours\" and clean up its own copy.",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Workspace id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "include",
            "description": "Comma-separated relations to populate. Allowed: creator, pipeline_stage, automations, action_suggestions, scheduled_sessions. A relation not requested is null. Nested paths (a.b) are not supported.",
            "required": false,
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "creator",
                  "pipeline_stage",
                  "automations",
                  "action_suggestions",
                  "scheduled_sessions"
                ]
              }
            }
          },
          {
            "in": "query",
            "name": "max_action_suggestions",
            "description": "Max action_suggestions per row (1..25, default 3). Ordered by expires_at asc. Requires include=action_suggestions.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 1,
              "maximum": 25
            }
          },
          {
            "in": "query",
            "name": "max_scheduled_sessions",
            "description": "Max scheduled_sessions per row (1..100, default 25). Ordered by date_time_start asc. Requires include=scheduled_sessions.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Get a workspace by id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_Workspace"
                }
              }
            }
          }
        },
        "tags": [
          "Workspaces"
        ],
        "operationId": "getWorkspace",
        "x-hb-resource": "workspaces",
        "security": [
          {
            "oauth2": [
              "workspaces.read"
            ]
          },
          {
            "oauth2": [
              "workspaces.read_own"
            ]
          }
        ]
      },
      "patch": {
        "summary": "Update a workspace (partial; renames the tab)",
        "description": "Only the workspace creator, an admin of the creator's company, or a member in that company may update; anyone else gets a 404.",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Workspace id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/updateWorkspace"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Update a workspace (partial; renames the tab)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_Workspace"
                }
              }
            }
          }
        },
        "tags": [
          "Workspaces"
        ],
        "operationId": "updateWorkspace",
        "x-hb-resource": "workspaces",
        "security": [
          {
            "oauth2": [
              "workspaces.write"
            ]
          },
          {
            "oauth2": [
              "workspaces.write_own"
            ]
          }
        ]
      },
      "delete": {
        "summary": "Delete a workspace",
        "description": "Archives the workspace and its files/flows to the graveyard and destroys it (and the Project when its last workspace is removed). Only the creator/owner/admin of the owning company may delete, and only when every file/flow is deletable (else 400).",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Workspace id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Delete a workspace"
          }
        },
        "tags": [
          "Workspaces"
        ],
        "operationId": "deleteWorkspace",
        "x-hb-resource": "workspaces",
        "security": [
          {
            "oauth2": [
              "workspaces.write"
            ]
          },
          {
            "oauth2": [
              "workspaces.write_own"
            ]
          }
        ]
      }
    },
    "/workspaces/{id}/deletable": {
      "get": {
        "summary": "Whether a workspace can be deleted by the caller",
        "description": "Members, and owners/admins of the creator's company, matching deleteWorkspace. Anyone else gets a 404. A false answer carries a `reason`: not_permitted (a client, a caller from another company, or a team member who is neither the creator nor an owner/admin) or has_undeletable_files (payments or a signed contract).",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Workspace id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Whether a workspace can be deleted by the caller",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_WorkspaceDeletable"
                }
              }
            }
          }
        },
        "tags": [
          "Workspaces"
        ],
        "operationId": "getWorkspaceDeletable",
        "x-hb-resource": "workspaces",
        "security": [
          {
            "oauth2": [
              "workspaces.read"
            ]
          },
          {
            "oauth2": [
              "workspaces.read_own"
            ]
          }
        ]
      }
    },
    "/workspaces/{id}/members": {
      "get": {
        "summary": "List a workspace's members",
        "description": "Only a workspace member, or a moderator-or-greater of the workspace's company, may read the member list; anyone else gets a 404.",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Workspace id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "page",
            "description": "1-indexed page number",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 1,
              "maximum": 1000000,
              "default": 1
            }
          },
          {
            "in": "query",
            "name": "per_page",
            "description": "Page size (max 100)",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "in": "query",
            "name": "include",
            "description": "Comma-separated relations to populate. Allowed: user, contact. A relation not requested is null. Nested paths (a.b) are not supported.",
            "required": false,
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "user",
                  "contact"
                ]
              }
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List a workspace's members",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_WorkspaceMember_Page"
                }
              }
            }
          }
        },
        "tags": [
          "Workspaces"
        ],
        "operationId": "listWorkspaceMembers",
        "x-hb-resource": "workspaces",
        "security": [
          {
            "oauth2": [
              "workspaces.read"
            ]
          },
          {
            "oauth2": [
              "workspaces.read_own"
            ]
          }
        ]
      }
    },
    "/workspaces/{id}/members/{user_id}": {
      "put": {
        "summary": "Add a member to a workspace (idempotent)",
        "description": "The caller must both participate in the workspace AND belong to the company that owns it; anyone else gets a 404. Returns the added membership row, the same shape listWorkspaceMembers returns, so a caller can read the contact it just gained without a second round trip.",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Workspace id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "user_id",
            "description": "User id to add — a team member of the caller's company, or anyone it holds a contact for and can see (a client, or a collaborator from another company)",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/addWorkspaceMember"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Add a member to a workspace (idempotent)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_WorkspaceMember"
                }
              }
            }
          }
        },
        "tags": [
          "Workspaces"
        ],
        "operationId": "addWorkspaceMember",
        "x-hb-resource": "workspaces",
        "security": [
          {
            "oauth2": [
              "workspaces.write"
            ]
          }
        ]
      },
      "delete": {
        "summary": "Remove a member from a workspace",
        "description": "Only the workspace creator or a super-admin of the creator's company may remove a member; anyone else gets a 404. Neither the creator nor the caller themselves can be removed (400).",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Workspace id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "user_id",
            "description": "Member user id to remove",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Remove a member from a workspace"
          }
        },
        "tags": [
          "Workspaces"
        ],
        "operationId": "removeWorkspaceMember",
        "x-hb-resource": "workspaces",
        "security": [
          {
            "oauth2": [
              "workspaces.write"
            ]
          },
          {
            "oauth2": [
              "workspaces.write_own"
            ]
          }
        ]
      }
    },
    "/workspaces/{id}/tags/{tag_id}": {
      "put": {
        "summary": "Tag a workspace (idempotent)",
        "description": "Members and super-admins of the creator's company only; anyone else gets a 404.",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Workspace id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "tag_id",
            "description": "Tag id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tag a workspace (idempotent)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_Workspace"
                }
              }
            }
          }
        },
        "tags": [
          "Workspaces"
        ],
        "operationId": "addWorkspaceTag",
        "x-hb-resource": "workspaces",
        "security": [
          {
            "oauth2": [
              "workspaces.write"
            ]
          },
          {
            "oauth2": [
              "workspaces.write_own"
            ]
          }
        ]
      },
      "delete": {
        "summary": "Untag a workspace (idempotent)",
        "description": "Members and super-admins of the creator's company only; anyone else gets a 404.",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Workspace id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "tag_id",
            "description": "Tag id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Untag a workspace (idempotent)"
          }
        },
        "tags": [
          "Workspaces"
        ],
        "operationId": "removeWorkspaceTag",
        "x-hb-resource": "workspaces",
        "security": [
          {
            "oauth2": [
              "workspaces.write"
            ]
          },
          {
            "oauth2": [
              "workspaces.write_own"
            ]
          }
        ]
      }
    },
    "/workspaces/{id}/archive": {
      "post": {
        "summary": "Archive a workspace for the caller and their team",
        "description": "Only a workspace member, or a super-admin of the creator's company, may archive; anyone else gets a 404.",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "description": "Optional, 1-255 printable ASCII. Retrying with the same key, path and body within 24h returns the first response verbatim (`Idempotent-Replayed: true`) instead of creating another. See the [Idempotency guide](#tag/idempotency).",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "id",
            "description": "Workspace id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/archiveWorkspace"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Archive a workspace for the caller and their team",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_Workspace"
                }
              }
            }
          }
        },
        "tags": [
          "Workspaces"
        ],
        "operationId": "archiveWorkspace",
        "x-hb-resource": "workspaces",
        "security": [
          {
            "oauth2": [
              "workspaces.write"
            ]
          },
          {
            "oauth2": [
              "workspaces.write_own"
            ]
          }
        ]
      }
    },
    "/workspaces/{id}/unarchive": {
      "post": {
        "summary": "Unarchive a workspace for the caller and their teammates",
        "description": "Only a workspace member, or a super-admin of the creator's company, may unarchive; anyone else gets a 404.",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "description": "Optional, 1-255 printable ASCII. Retrying with the same key, path and body within 24h returns the first response verbatim (`Idempotent-Replayed: true`) instead of creating another. See the [Idempotency guide](#tag/idempotency).",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "id",
            "description": "Workspace id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Unarchive a workspace for the caller and their teammates",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_Workspace"
                }
              }
            }
          }
        },
        "tags": [
          "Workspaces"
        ],
        "operationId": "unarchiveWorkspace",
        "x-hb-resource": "workspaces",
        "security": [
          {
            "oauth2": [
              "workspaces.write"
            ]
          },
          {
            "oauth2": [
              "workspaces.write_own"
            ]
          }
        ]
      }
    },
    "/workspaces/{id}/book": {
      "post": {
        "summary": "Book a workspace (mark the project as booked)",
        "description": "Sets status to `client` and advances the pipeline stage to the company's paid stage (else signed, else the first projects-group stage), only when that is forward of the current one. A no-op on an already-booked workspace. Only the workspace creator, an admin of the creator's company, or a member in that company may book; anyone else gets a 404. 403 when the caller's `mark_project_as_booked` gate is off; 422 when the workspace has no project, is archived, or the company resolves no target stage.",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "description": "Optional, 1-255 printable ASCII. Retrying with the same key, path and body within 24h returns the first response verbatim (`Idempotent-Replayed: true`) instead of creating another. See the [Idempotency guide](#tag/idempotency).",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "id",
            "description": "Workspace id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/bookWorkspace"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Book a workspace (mark the project as booked)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_Workspace"
                }
              }
            }
          }
        },
        "tags": [
          "Workspaces"
        ],
        "operationId": "bookWorkspace",
        "x-hb-resource": "workspaces",
        "security": [
          {
            "oauth2": [
              "workspaces.write"
            ]
          },
          {
            "oauth2": [
              "workspaces.write_own"
            ]
          }
        ]
      }
    },
    "/lead_sources": {
      "get": {
        "summary": "List the caller company's lead sources",
        "description": "The company's catalog holds at most 18 lead sources, so one page returns all of them.",
        "parameters": [
          {
            "in": "query",
            "name": "page",
            "description": "1-indexed page number",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 1,
              "maximum": 1000000,
              "default": 1
            }
          },
          {
            "in": "query",
            "name": "per_page",
            "description": "Page size (max 18)",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 1,
              "maximum": 18,
              "default": 18
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List the caller company's lead sources",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_LeadSource_Page"
                }
              }
            }
          }
        },
        "tags": [
          "LeadSources"
        ],
        "operationId": "listLeadSources",
        "x-hb-resource": "lead_sources",
        "security": [
          {
            "oauth2": [
              "account.read"
            ]
          }
        ]
      },
      "post": {
        "summary": "Create a lead source",
        "description": "400 when the company already has 18 lead sources. 409 when the label already exists or a previous lead source change is still being applied to projects and contact forms.",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "description": "Optional, 1-255 printable ASCII. Retrying with the same key, path and body within 24h returns the first response verbatim (`Idempotent-Replayed: true`) instead of creating another. See the [Idempotency guide](#tag/idempotency).",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/createLeadSource"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Create a lead source",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_LeadSource"
                }
              }
            }
          }
        },
        "tags": [
          "LeadSources"
        ],
        "operationId": "createLeadSource",
        "x-hb-resource": "lead_sources",
        "security": [
          {
            "oauth2": [
              "account.write"
            ]
          }
        ]
      }
    },
    "/lead_sources/{id}": {
      "get": {
        "summary": "Get a lead source",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Lead source id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Get a lead source",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_LeadSource"
                }
              }
            }
          }
        },
        "tags": [
          "LeadSources"
        ],
        "operationId": "getLeadSource",
        "x-hb-resource": "lead_sources",
        "security": [
          {
            "oauth2": [
              "account.read"
            ]
          }
        ]
      },
      "patch": {
        "summary": "Rename a lead source",
        "description": "400 for system lead sources (\"Other\", \"Unknown\"). 409 when the label already exists or a previous lead source change is still being applied.",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Lead source id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/updateLeadSource"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Rename a lead source",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_LeadSource"
                }
              }
            }
          }
        },
        "tags": [
          "LeadSources"
        ],
        "operationId": "updateLeadSource",
        "x-hb-resource": "lead_sources",
        "security": [
          {
            "oauth2": [
              "account.write"
            ]
          }
        ]
      },
      "delete": {
        "summary": "Delete a lead source; its projects are reassigned to \"Other\"",
        "description": "400 for system lead sources (\"Other\", \"Unknown\"). 409 while a previous lead source change is still being applied.",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Lead source id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Delete a lead source; its projects are reassigned to \"Other\""
          }
        },
        "tags": [
          "LeadSources"
        ],
        "operationId": "deleteLeadSource",
        "x-hb-risk": {
          "level": "dangerous",
          "reason": "Reassigns the lead source's projects to \"Other\" and removes it from contact forms."
        },
        "x-hb-resource": "lead_sources",
        "security": [
          {
            "oauth2": [
              "account.write"
            ]
          }
        ]
      }
    },
    "/projects": {
      "get": {
        "summary": "List the projects the caller can read",
        "description": "A moderator or greater reads every project their company owns plus those they are a member of through a workspace; any other member reads only the projects they are a member of. `member_ids` narrows that set and never widens it: for a member below moderator it can only name themselves, any other id matches nothing.",
        "parameters": [
          {
            "in": "query",
            "name": "page",
            "description": "1-indexed page number",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 1,
              "maximum": 1000000,
              "default": 1
            }
          },
          {
            "in": "query",
            "name": "per_page",
            "description": "Page size (max 100)",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "in": "query",
            "name": "include",
            "description": "Comma-separated relations to populate. Allowed: workspaces, custom_fields, cover_image. A relation not requested is null. Nested paths (a.b) are not supported.",
            "required": false,
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "workspaces",
                  "custom_fields",
                  "cover_image"
                ]
              }
            }
          },
          {
            "in": "query",
            "name": "max_workspaces",
            "description": "Max workspaces per row (1..25, default 25). Ordered by created_at asc. Requires include=workspaces.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 1,
              "maximum": 25
            }
          },
          {
            "in": "query",
            "name": "max_custom_fields",
            "description": "Max custom_fields per row (1..50, default 50). Ordered by order asc. Requires include=custom_fields.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 1,
              "maximum": 50
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "in": "query",
            "name": "member_ids",
            "description": "Narrow to rows these members belong to (comma-separated user ids). A caller below moderator can only narrow to themselves; other ids match nothing",
            "required": false,
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "in": "query",
            "name": "name_contains",
            "description": "event_name contains (case-insensitive)",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "project_type_id",
            "description": "project_type =",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "project_after",
            "description": "event_date >=",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "in": "query",
            "name": "project_before",
            "description": "event_date <=",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "in": "query",
            "name": "payroll_employee_ids",
            "description": "payroll_employees in (comma-separated)",
            "required": false,
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "in": "query",
            "name": "created_after",
            "description": "created_at >=",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "in": "query",
            "name": "created_before",
            "description": "created_at <=",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "in": "query",
            "name": "sort",
            "description": "Comma-separated sort keys; '-' prefix = descending. Allowed: created_at, project_date, name. Default: -created_at.",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List the projects the caller can read",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_Project_Page"
                }
              }
            }
          }
        },
        "tags": [
          "Projects"
        ],
        "operationId": "listProjects",
        "x-hb-resource": "projects",
        "security": [
          {
            "oauth2": [
              "projects.read"
            ]
          },
          {
            "oauth2": [
              "projects.read_own"
            ]
          }
        ]
      },
      "post": {
        "summary": "Create a project",
        "description": "Creates the project and its first workspace. Ask for `?include=workspaces` to get that workspace back in this response — `workspaces.data[0].id` is the id needed to add a member to the new project (PUT /workspaces/:id/members/:user_id), so a caller does not have to discover it with a second call.",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "description": "Optional, 1-255 printable ASCII. Retrying with the same key, path and body within 24h returns the first response verbatim (`Idempotent-Replayed: true`) instead of creating another. See the [Idempotency guide](#tag/idempotency).",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/createProject"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Create a project",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_Project"
                }
              }
            }
          }
        },
        "tags": [
          "Projects"
        ],
        "operationId": "createProject",
        "x-hb-resource": "projects",
        "security": [
          {
            "oauth2": [
              "projects.write"
            ]
          },
          {
            "oauth2": [
              "projects.write_own"
            ]
          }
        ]
      }
    },
    "/projects/payroll_employee_counts": {
      "get": {
        "summary": "Project counts per payroll employee (batch)",
        "parameters": [
          {
            "in": "query",
            "name": "employee_ids",
            "description": "Comma-separated payroll employee ids",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Project counts per payroll employee (batch)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_ProjectPayrollEmployeeCount"
                }
              }
            }
          }
        },
        "tags": [
          "Projects"
        ],
        "operationId": "getProjectPayrollEmployeeCounts",
        "x-hb-resource": "projects",
        "security": [
          {
            "oauth2": [
              "projects.read"
            ]
          }
        ]
      }
    },
    "/projects/{id}": {
      "get": {
        "summary": "Get a project by id",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Project id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "include",
            "description": "Comma-separated relations to populate. Allowed: workspaces, custom_fields, cover_image. A relation not requested is null. Nested paths (a.b) are not supported.",
            "required": false,
            "style": "form",
            "explode": false,
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "workspaces",
                  "custom_fields",
                  "cover_image"
                ]
              }
            }
          },
          {
            "in": "query",
            "name": "max_workspaces",
            "description": "Max workspaces per row (1..25, default 25). Ordered by created_at asc. Requires include=workspaces.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 1,
              "maximum": 25
            }
          },
          {
            "in": "query",
            "name": "max_custom_fields",
            "description": "Max custom_fields per row (1..50, default 50). Ordered by order asc. Requires include=custom_fields.",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 1,
              "maximum": 50
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Get a project by id",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_Project"
                }
              }
            }
          }
        },
        "tags": [
          "Projects"
        ],
        "operationId": "getProject",
        "x-hb-resource": "projects",
        "security": [
          {
            "oauth2": [
              "projects.read"
            ]
          },
          {
            "oauth2": [
              "projects.read_own"
            ]
          }
        ]
      },
      "patch": {
        "summary": "Update a project (partial; data fields only)",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Project id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/updateProject"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Update a project (partial; data fields only)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_Project"
                }
              }
            }
          }
        },
        "tags": [
          "Projects"
        ],
        "operationId": "updateProject",
        "x-hb-resource": "projects",
        "security": [
          {
            "oauth2": [
              "projects.write"
            ]
          },
          {
            "oauth2": [
              "projects.write_own"
            ]
          }
        ]
      }
    },
    "/projects/{id}/dates": {
      "post": {
        "summary": "Add a project date",
        "description": "Appends a new, empty additional date with an auto-generated default label; populate its fields afterwards via PATCH /projects/:id/dates/:date_id.",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "description": "Optional, 1-255 printable ASCII. Retrying with the same key, path and body within 24h returns the first response verbatim (`Idempotent-Replayed: true`) instead of creating another. See the [Idempotency guide](#tag/idempotency).",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "id",
            "description": "Project id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Add a project date",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_ProjectDate"
                }
              }
            }
          }
        },
        "tags": [
          "Projects"
        ],
        "operationId": "createProjectDate",
        "x-hb-resource": "projects",
        "security": [
          {
            "oauth2": [
              "projects.write"
            ]
          },
          {
            "oauth2": [
              "projects.write_own"
            ]
          }
        ]
      }
    },
    "/projects/{id}/dates/{date_id}": {
      "patch": {
        "summary": "Update a project date (partial)",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Project id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "date_id",
            "description": "Project date id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/updateProjectDate"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Update a project date (partial)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_ProjectDate"
                }
              }
            }
          }
        },
        "tags": [
          "Projects"
        ],
        "operationId": "updateProjectDate",
        "x-hb-resource": "projects",
        "security": [
          {
            "oauth2": [
              "projects.write"
            ]
          },
          {
            "oauth2": [
              "projects.write_own"
            ]
          }
        ]
      },
      "delete": {
        "summary": "Delete a project date",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Project id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "date_id",
            "description": "Project date id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Delete a project date"
          }
        },
        "tags": [
          "Projects"
        ],
        "operationId": "deleteProjectDate",
        "x-hb-resource": "projects",
        "security": [
          {
            "oauth2": [
              "projects.write"
            ]
          },
          {
            "oauth2": [
              "projects.write_own"
            ]
          }
        ]
      }
    },
    "/projects/{id}/payroll_employees": {
      "get": {
        "summary": "List a project's payroll employees",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Project id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List a project's payroll employees",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_ProjectPayrollEmployees"
                }
              }
            }
          }
        },
        "tags": [
          "Projects"
        ],
        "operationId": "listProjectPayrollEmployees",
        "x-hb-resource": "projects",
        "security": [
          {
            "oauth2": [
              "projects.read"
            ]
          },
          {
            "oauth2": [
              "projects.read_own"
            ]
          }
        ]
      }
    },
    "/projects/{id}/payroll_employees/{employee_id}": {
      "put": {
        "summary": "Assign a payroll employee to a project (idempotent)",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Project id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "employee_id",
            "description": "Payroll employee id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Assign a payroll employee to a project (idempotent)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_Project"
                }
              }
            }
          }
        },
        "tags": [
          "Projects"
        ],
        "operationId": "addProjectPayrollEmployee",
        "x-hb-resource": "projects",
        "security": [
          {
            "oauth2": [
              "projects.write"
            ]
          },
          {
            "oauth2": [
              "projects.write_own"
            ]
          }
        ]
      },
      "delete": {
        "summary": "Remove a payroll employee from a project",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Project id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "employee_id",
            "description": "Payroll employee id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Remove a payroll employee from a project"
          }
        },
        "tags": [
          "Projects"
        ],
        "operationId": "removeProjectPayrollEmployee",
        "x-hb-resource": "projects",
        "security": [
          {
            "oauth2": [
              "projects.write"
            ]
          },
          {
            "oauth2": [
              "projects.write_own"
            ]
          }
        ]
      }
    },
    "/projects/{id}/spaces/{space_id}": {
      "put": {
        "summary": "Add a company space (a named venue/location from the company's spaces) to a project (idempotent)",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Project id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "space_id",
            "description": "Company space id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Add a company space (a named venue/location from the company's spaces) to a project (idempotent)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_Project"
                }
              }
            }
          }
        },
        "tags": [
          "Projects"
        ],
        "operationId": "addProjectSpace",
        "x-hb-resource": "projects",
        "security": [
          {
            "oauth2": [
              "projects.write"
            ]
          },
          {
            "oauth2": [
              "projects.write_own"
            ]
          }
        ]
      },
      "delete": {
        "summary": "Remove a company space from a project",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Project id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "space_id",
            "description": "Company space id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Remove a company space from a project"
          }
        },
        "tags": [
          "Projects"
        ],
        "operationId": "removeProjectSpace",
        "x-hb-resource": "projects",
        "security": [
          {
            "oauth2": [
              "projects.write"
            ]
          },
          {
            "oauth2": [
              "projects.write_own"
            ]
          }
        ]
      }
    },
    "/projects/{id}/conflicts": {
      "get": {
        "summary": "Get scheduling conflicts for a project",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Project id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Get scheduling conflicts for a project",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_ProjectConflicts"
                }
              }
            }
          }
        },
        "tags": [
          "Projects"
        ],
        "operationId": "getProjectConflicts",
        "x-hb-resource": "projects",
        "security": [
          {
            "oauth2": [
              "projects.read"
            ]
          }
        ]
      }
    },
    "/projects/{id}/workspaces": {
      "post": {
        "summary": "Create a workspace on a project",
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "description": "Optional, 1-255 printable ASCII. Retrying with the same key, path and body within 24h returns the first response verbatim (`Idempotent-Replayed: true`) instead of creating another. See the [Idempotency guide](#tag/idempotency).",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "id",
            "description": "Project id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/createProjectWorkspace"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Create a workspace on a project",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_Workspace"
                }
              }
            }
          }
        },
        "tags": [
          "Projects",
          "Workspaces"
        ],
        "operationId": "createProjectWorkspace",
        "x-hb-resource": "projects",
        "security": [
          {
            "oauth2": [
              "projects.write"
            ]
          },
          {
            "oauth2": [
              "projects.write_own"
            ]
          }
        ]
      }
    },
    "/projects/{id}/custom_fields": {
      "get": {
        "summary": "List a project's custom field values",
        "description": "One row per LIVE custom field the company defines for projects, whether or not this project has a value for it — `value` is null (or `[]` for multi_select) when unset, which is how a caller learns the field exists and is empty. Narrow on `type` to read `value`: a String for text/long_text/link, a number for number, an ISO8601 date for date, and the selected option object(s) for the selects. Same rows as `?include=custom_fields`; one default page holds them all.",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Project id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "in": "query",
            "name": "page",
            "description": "1-indexed page number",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 1,
              "maximum": 1000000,
              "default": 1
            }
          },
          {
            "in": "query",
            "name": "per_page",
            "description": "Page size (max 500)",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32",
              "minimum": 1,
              "maximum": 500,
              "default": 500
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List a project's custom field values",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_CustomFieldValue_Page"
                }
              }
            }
          }
        },
        "tags": [
          "Projects",
          "CustomFields"
        ],
        "operationId": "listProjectCustomFields",
        "x-hb-resource": "projects",
        "security": [
          {
            "oauth2": [
              "projects.read"
            ]
          },
          {
            "oauth2": [
              "projects.read_own"
            ]
          }
        ]
      }
    },
    "/projects/{id}/custom_fields/{field_id}": {
      "patch": {
        "summary": "Set a project's value for one custom field",
        "description": "The field id in the path already fixes the type, so `value` is sent as a String for every kind and coerced server-side: a number as its digits (\"42\"), a date as ISO8601 (\"2026-09-15\"), a single_select as the chosen option's id, a multi_select as a comma-separated list of option ids. A value the field's type rejects is a 400. Returns the field's node, so the caller sees the stored, coerced result.",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Project id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "field_id",
            "description": "Custom field id (the `id` of a GET /custom_fields row)",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/updateProjectCustomField"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Set a project's value for one custom field",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Api_V3_Entities_CustomFieldValue"
                }
              }
            }
          }
        },
        "tags": [
          "Projects",
          "CustomFields"
        ],
        "operationId": "updateProjectCustomField",
        "x-hb-resource": "projects",
        "security": [
          {
            "oauth2": [
              "projects.write"
            ]
          },
          {
            "oauth2": [
              "projects.write_own"
            ]
          }
        ]
      },
      "delete": {
        "summary": "Clear a project's value for one custom field",
        "description": "The field itself is untouched — it stays on every project, including this one, with no value. Deleting the FIELD is DELETE /custom_fields/:id.",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "description": "Project id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "field_id",
            "description": "Custom field id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "partner_only",
            "description": "`true` restricts the request to records your integration created: lists and reads return only those, and updates and deletes reach only those (anything else is a 404). Omit or `false` reaches everything the granted scope allows, and requires the full scope. Creates accept `true` and always record your integration as the creator.",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Clear a project's value for one custom field"
          }
        },
        "tags": [
          "Projects",
          "CustomFields"
        ],
        "operationId": "clearProjectCustomField",
        "x-hb-resource": "projects",
        "security": [
          {
            "oauth2": [
              "projects.write"
            ]
          },
          {
            "oauth2": [
              "projects.write_own"
            ]
          }
        ]
      }
    }
  },
  "servers": [
    {
      "url": "https://api.honeybook.com/api/v3",
      "description": "Production"
    }
  ],
  "components": {
    "securitySchemes": {
      "oauth2": {
        "type": "oauth2",
        "x-hb-automatic-scopes": [
          "offline_access",
          "honeybook.api",
          "openid"
        ],
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://oauth.honeybook.com/oauth2/auth",
            "tokenUrl": "https://oauth.honeybook.com/oauth2/token",
            "scopes": {
              "offline_access": "Obtain a refresh token so access can outlive a single token lifetime",
              "honeybook.api": "General access to the HoneyBook API, granted with every token; on its own it only unlocks endpoints that have no resource-specific scope",
              "openid": "Identify the HoneyBook account that signed in. Used by sign-in flows",
              "account.read": "Read the current user's profile and settings",
              "account.write": "Update the current user's profile and settings",
              "contacts.read": "Read contacts, their tags and lead-source attribution",
              "contacts.read_own": "Read only the contacts your integration created, by sending partner_only=true",
              "contacts.write": "Create, update and delete contacts, and manage their tags",
              "contacts.write_own": "Create contacts and change only the ones your integration created, by sending partner_only=true",
              "projects.read": "Read projects, their payroll employees and scheduling conflicts, and the company's project types",
              "projects.read_own": "Read only the projects your integration created, by sending partner_only=true to the project endpoints, and the company's project types, where the flag is not sent",
              "projects.write": "Create and update projects, manage their dates, spaces and payroll employees, and manage the company's project types",
              "projects.write_own": "Create projects and change only the ones your integration created, by sending partner_only=true",
              "workspaces.read": "Read workspaces, their members and legacy files, and the pipeline",
              "workspaces.read_own": "Read only the workspaces your integration created, by sending partner_only=true",
              "workspaces.write": "Update, archive, book and delete workspaces, move them between pipeline stages, and manage their members and tags",
              "workspaces.write_own": "Change only the workspaces your integration created, by sending partner_only=true"
            },
            "refreshUrl": "https://oauth.honeybook.com/oauth2/token"
          }
        },
        "description": "OAuth 2.0 authorization code flow with PKCE. See the Authentication guide."
      }
    },
    "schemas": {
      "Api_V3_Entities_SmartFile_Block_AvailabilityCalendarBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_ChargeBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "allow_gratuity": {
            "type": "boolean",
            "description": "Whether the client may add a gratuity at checkout"
          },
          "allow_autopay": {
            "type": "boolean",
            "description": "Whether automatic recurring payments are available"
          },
          "gratuity_type": {
            "type": "string",
            "enum": [
              "all_payments",
              "last_payment"
            ],
            "description": "When gratuity is offered: all_payments (every installment) or last_payment (final one only)",
            "nullable": true
          },
          "gratuity_calculation_base": {
            "type": "string",
            "enum": [
              "entire_invoice",
              "current_payment"
            ],
            "description": "The amount gratuity is calculated on: entire_invoice or current_payment",
            "nullable": true
          },
          "allowed_payment_methods": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "general",
                "credit_card",
                "bank_account",
                "manual",
                "finance_app"
              ]
            },
            "description": "Payment methods the client may choose from (restricted per company and flow setup)"
          },
          "pass_fee_to_client": {
            "type": "boolean",
            "description": "Whether to charge the client the platform fee (nil for blocks created before the feature shipped)",
            "nullable": true
          },
          "pass_fee_to_client_tax_rate": {
            "type": "number",
            "format": "float",
            "description": "Tax rate (0-100) the member applies to the client processing fee, if any. Defaults to 0."
          },
          "affirm_enabled": {
            "type": "boolean",
            "description": "Whether Affirm pay-over-time is offered as a payment method"
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes",
          "allow_gratuity",
          "allow_autopay",
          "gratuity_type",
          "gratuity_calculation_base",
          "allowed_payment_methods",
          "pass_fee_to_client",
          "pass_fee_to_client_tax_rate",
          "affirm_enabled"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_ChargeContainerBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "layout_type": {
            "type": "string",
            "enum": [
              "vertical",
              "horizontal"
            ],
            "description": "Whether this container stacks its children or lays them out side by side"
          },
          "composition_type": {
            "type": "string",
            "enum": [
              "default",
              "company_info"
            ],
            "description": "Which prebuilt composition this container is an instance of"
          },
          "children_layout": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_ChildLayout"
            },
            "description": "The blocks inside this container — each named by `block_id`, with how much room it gets and in what order. Look each one up in the file's `blocks`. Absent on blocks that cannot nest."
          },
          "container_title": {
            "type": "string",
            "description": "Vendor-facing label for the container in the builder"
          },
          "source_flow_id": {
            "type": "string",
            "description": "Id of the smart file this container was copied in from"
          },
          "background_image": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_Image"
              }
            ],
            "description": "Picture drawn behind the container"
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_ChildLayout": {
        "type": "object",
        "properties": {
          "block_id": {
            "type": "string",
            "description": "Id of the block in this slot, to look up in the file's `blocks`. Null on a slot whose block is gone — skip it rather than treating it as content.",
            "nullable": true
          },
          "size": {
            "type": "number",
            "format": "float",
            "description": "Share of the container the child occupies, as a fraction of the whole"
          },
          "order": {
            "type": "number",
            "format": "float",
            "description": "Sort position among siblings; fractional values are normal"
          }
        },
        "required": [
          "block_id",
          "size",
          "order"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_Image": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Image id (BSON ObjectId hex)",
            "nullable": true
          },
          "url": {
            "type": "string",
            "description": "Where the image is served from",
            "nullable": true
          },
          "original_url": {
            "type": "string",
            "description": "The upload as it arrived, before any crop or resize",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Original file name of the upload",
            "nullable": true
          },
          "file_type": {
            "type": "string",
            "description": "MIME type of the upload",
            "nullable": true
          },
          "cloudinary_public_id": {
            "type": "string",
            "description": "Cloudinary id, for building transformed variants",
            "nullable": true
          },
          "cloudinary_sub_account": {
            "type": "string",
            "description": "Which Cloudinary account serves it",
            "nullable": true
          },
          "width": {
            "type": "integer",
            "format": "int32",
            "description": "Intrinsic width in pixels",
            "nullable": true
          },
          "height": {
            "type": "integer",
            "format": "int32",
            "description": "Intrinsic height in pixels",
            "nullable": true
          },
          "position_left": {
            "type": "string",
            "description": "Horizontal offset of the picture within its frame, as a CSS length",
            "nullable": true
          },
          "position_top": {
            "type": "string",
            "description": "Vertical offset of the picture within its frame, as a CSS length",
            "nullable": true
          },
          "position_x": {
            "type": "integer",
            "format": "int32",
            "description": "Left edge of the crop box, in pixels of the original",
            "nullable": true
          },
          "position_y": {
            "type": "integer",
            "format": "int32",
            "description": "Top edge of the crop box, in pixels of the original",
            "nullable": true
          },
          "position_w": {
            "type": "integer",
            "format": "int32",
            "description": "Width of the crop box, in pixels of the original",
            "nullable": true
          },
          "position_h": {
            "type": "integer",
            "format": "int32",
            "description": "Height of the crop box, in pixels of the original",
            "nullable": true
          },
          "crop_ratio": {
            "type": "string",
            "description": "Aspect ratio the crop box is locked to (e.g. \"16:9\")",
            "nullable": true
          },
          "crop_type": {
            "type": "string",
            "enum": [
              "pad"
            ],
            "description": "How the picture fills a frame it does not match",
            "nullable": true
          },
          "resize_ratio": {
            "type": "number",
            "format": "float",
            "description": "Scale applied to the original before cropping",
            "nullable": true
          },
          "focal_point_x": {
            "type": "number",
            "format": "float",
            "description": "Horizontal point to keep in view when the frame crops the picture, 0 to 1 from the left",
            "nullable": true
          },
          "focal_point_y": {
            "type": "number",
            "format": "float",
            "description": "Vertical point to keep in view when the frame crops the picture, 0 to 1 from the top",
            "nullable": true
          },
          "phash": {
            "type": "string",
            "description": "Perceptual hash, used to recognize the same picture uploaded twice",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the image was uploaded (ISO8601)",
            "nullable": true
          }
        },
        "required": [
          "id",
          "url",
          "original_url",
          "name",
          "file_type",
          "cloudinary_public_id",
          "cloudinary_sub_account",
          "width",
          "height",
          "position_left",
          "position_top",
          "position_x",
          "position_y",
          "position_w",
          "position_h",
          "crop_ratio",
          "crop_type",
          "resize_ratio",
          "focal_point_x",
          "focal_point_y",
          "phash",
          "created_at"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_CompanyInfoBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "layout_type": {
            "type": "string",
            "enum": [
              "vertical",
              "horizontal"
            ],
            "description": "Whether this container stacks its children or lays them out side by side"
          },
          "composition_type": {
            "type": "string",
            "enum": [
              "default",
              "company_info"
            ],
            "description": "Which prebuilt composition this container is an instance of"
          },
          "children_layout": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_ChildLayout"
            },
            "description": "The blocks inside this container — each named by `block_id`, with how much room it gets and in what order. Look each one up in the file's `blocks`. Absent on blocks that cannot nest."
          },
          "container_title": {
            "type": "string",
            "description": "Vendor-facing label for the container in the builder"
          },
          "source_flow_id": {
            "type": "string",
            "description": "Id of the smart file this container was copied in from"
          },
          "background_image": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_Image"
              }
            ],
            "description": "Picture drawn behind the container"
          },
          "company_info_layout_type": {
            "type": "string",
            "enum": [
              "logo_on_left",
              "centered",
              "logo_on_right",
              "header",
              "stacked_left",
              "footer",
              "footer_centered",
              "logo_only",
              "hero",
              "beo_header"
            ],
            "description": "How the block arranges the logo and the company details",
            "nullable": true
          },
          "linked_to_company_settings": {
            "type": "boolean",
            "description": "Whether the company info reflects the active company settings",
            "nullable": true
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes",
          "company_info_layout_type",
          "linked_to_company_settings"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_ContainerBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "layout_type": {
            "type": "string",
            "enum": [
              "vertical",
              "horizontal"
            ],
            "description": "Whether this container stacks its children or lays them out side by side"
          },
          "composition_type": {
            "type": "string",
            "enum": [
              "default",
              "company_info"
            ],
            "description": "Which prebuilt composition this container is an instance of"
          },
          "children_layout": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_ChildLayout"
            },
            "description": "The blocks inside this container — each named by `block_id`, with how much room it gets and in what order. Look each one up in the file's `blocks`. Absent on blocks that cannot nest."
          },
          "container_title": {
            "type": "string",
            "description": "Vendor-facing label for the container in the builder"
          },
          "source_flow_id": {
            "type": "string",
            "description": "Id of the smart file this container was copied in from"
          },
          "background_image": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_Image"
              }
            ],
            "description": "Picture drawn behind the container"
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_ContractBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "layout_type": {
            "type": "string",
            "enum": [
              "vertical",
              "horizontal"
            ],
            "description": "Whether this container stacks its children or lays them out side by side"
          },
          "composition_type": {
            "type": "string",
            "enum": [
              "default",
              "company_info"
            ],
            "description": "Which prebuilt composition this container is an instance of"
          },
          "children_layout": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_ChildLayout"
            },
            "description": "The blocks inside this container — each named by `block_id`, with how much room it gets and in what order. Look each one up in the file's `blocks`. Absent on blocks that cannot nest."
          },
          "container_title": {
            "type": "string",
            "description": "Vendor-facing label for the container in the builder"
          },
          "source_flow_id": {
            "type": "string",
            "description": "Id of the smart file this container was copied in from"
          },
          "background_image": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_Image"
              }
            ],
            "description": "Picture drawn behind the container"
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_ContractHtmlBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "contract": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_Contract"
              }
            ],
            "description": "The contract HTML and its fields",
            "nullable": true
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes",
          "contract"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_Contract": {
        "type": "object",
        "properties": {
          "html_body": {
            "type": "string",
            "description": "The contract HTML, with embedded field markers",
            "nullable": true
          },
          "fields_metadata": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_Contract_FieldMetadata"
            },
            "description": "Metadata for each smart field in the contract"
          }
        },
        "required": [
          "html_body",
          "fields_metadata"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_Contract_FieldMetadata": {
        "type": "object",
        "properties": {
          "field_id": {
            "type": "string",
            "description": "Unique id for this field within the contract (UUID)"
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding the client input for this field",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "User-facing label for the field",
            "nullable": true
          },
          "type": {
            "type": "string",
            "enum": [
              "field",
              "services_recap",
              "payments_recap"
            ],
            "description": "What kind of field: a normal input, a services recap, or a payments recap"
          },
          "placeholder": {
            "type": "string",
            "description": "Hint text shown when the field is empty",
            "nullable": true
          },
          "default_value": {
            "type": "string",
            "description": "Value pre-filled in the field, for manual inputs or empty for linked fields",
            "nullable": true
          },
          "fill_type": {
            "type": "string",
            "enum": [
              "client_optional",
              "client_required",
              "vendor_required"
            ],
            "description": "Whether the field is optional or required, and whether the client or vendor fills it",
            "nullable": true
          },
          "data_source_type": {
            "type": "string",
            "enum": [
              "flow",
              "company",
              "project",
              "project_date",
              "custom",
              "first_client",
              "second_client",
              "third_client",
              "payments",
              "invoice",
              "session",
              "custom_contact_fields_first_client",
              "custom_contact_fields_second_client",
              "custom_contact_fields_third_client"
            ],
            "description": "Where the field value comes from: flow metadata, company info, project details, or a custom field",
            "nullable": true
          },
          "data_source_property": {
            "type": "string",
            "description": "Which property of the data source is linked to this field",
            "nullable": true
          },
          "data_source_sub_property": {
            "type": "string",
            "description": "A sub-level of the data source property, for nested data",
            "nullable": true
          }
        },
        "required": [
          "field_id",
          "connected_variable_id",
          "name",
          "type",
          "placeholder",
          "default_value",
          "fill_type",
          "data_source_type",
          "data_source_property",
          "data_source_sub_property"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_EventTimelineBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "name": {
            "type": "string",
            "description": "The block label for the event timeline section",
            "nullable": true
          },
          "event_timeline_id": {
            "type": "string",
            "description": "The linked event timeline, as an object id. Present only while the block is live, unpublished or frozen."
          },
          "event_timeline_title": {
            "type": "string",
            "description": "Title of the linked timeline. Present only while the block is live."
          },
          "unfinished_item_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Ids of the timeline items that have no title. Present only while the block is unpublished; sending the file is refused until none are left."
          },
          "state": {
            "type": "string",
            "enum": [
              "frozen",
              "live",
              "unpublished",
              "empty",
              "unavailable"
            ],
            "description": "frozen: the file was signed and shows the timeline as it was then. live: the timeline is published and shown. unpublished: the linked timeline is not published yet. empty: nothing is linked, the link no longer applies, or event timelines are off for the company. unavailable: the timeline could not be read, or could not be frozen at signing."
          },
          "frozen_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the block froze at signing. Present only once the file was signed with a live timeline."
          },
          "timeline": {
            "type": "object",
            "description": "The Everyone view of the linked timeline: title, time_zone, version and days with their Everyone items. Null unless the block is live or frozen.",
            "nullable": true
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes",
          "name",
          "state",
          "timeline"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_FileSignatureBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "layout_type": {
            "type": "string",
            "enum": [
              "vertical",
              "horizontal"
            ],
            "description": "Whether this container stacks its children or lays them out side by side"
          },
          "composition_type": {
            "type": "string",
            "enum": [
              "default",
              "company_info"
            ],
            "description": "Which prebuilt composition this container is an instance of"
          },
          "children_layout": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_ChildLayout"
            },
            "description": "The blocks inside this container — each named by `block_id`, with how much room it gets and in what order. Look each one up in the file's `blocks`. Absent on blocks that cannot nest."
          },
          "container_title": {
            "type": "string",
            "description": "Vendor-facing label for the container in the builder"
          },
          "source_flow_id": {
            "type": "string",
            "description": "Id of the smart file this container was copied in from"
          },
          "background_image": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_Image"
              }
            ],
            "description": "Picture drawn behind the container"
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_FloorPlanBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "name": {
            "type": "string",
            "description": "The block label for the floor plan section",
            "nullable": true
          },
          "floor_plan_id": {
            "type": "string",
            "description": "The floor plan selected, as UUID"
          },
          "floor_plan_name": {
            "type": "string",
            "description": "Name of the selected floor plan"
          },
          "floor_plan_resize_ratio": {
            "type": "number",
            "format": "float",
            "description": "How much the plan image is scaled in the block. Absent when it has not been resized."
          },
          "floor_plan_thumbnail_url": {
            "type": "string",
            "description": "Preview image of the floor plan (URL). Omitted until the plan is rendered."
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes",
          "name"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_IframeBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "url": {
            "type": "string",
            "description": "Embedded page URL",
            "nullable": true
          },
          "height": {
            "type": "integer",
            "format": "int32",
            "description": "Frame height in pixels",
            "nullable": true
          },
          "width": {
            "type": "integer",
            "format": "int32",
            "description": "Frame width, as a percentage of the content column",
            "nullable": true
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes",
          "url",
          "height",
          "width"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_ImageBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "image": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_Image"
              }
            ],
            "description": "The picture",
            "nullable": true
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes",
          "image"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_InvoiceColumnHeaderBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_InvoiceContainerBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "layout_type": {
            "type": "string",
            "enum": [
              "vertical",
              "horizontal"
            ],
            "description": "Whether this container stacks its children or lays them out side by side"
          },
          "composition_type": {
            "type": "string",
            "enum": [
              "default",
              "company_info"
            ],
            "description": "Which prebuilt composition this container is an instance of"
          },
          "children_layout": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_ChildLayout"
            },
            "description": "The blocks inside this container — each named by `block_id`, with how much room it gets and in what order. Look each one up in the file's `blocks`. Absent on blocks that cannot nest."
          },
          "container_title": {
            "type": "string",
            "description": "Vendor-facing label for the container in the builder"
          },
          "source_flow_id": {
            "type": "string",
            "description": "Id of the smart file this container was copied in from"
          },
          "background_image": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_Image"
              }
            ],
            "description": "Picture drawn behind the container"
          },
          "sub_total": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_Money"
              }
            ],
            "description": "What the line items come to before tax and discount, as Money"
          },
          "total_tax": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_Money"
              }
            ],
            "description": "Tax added on top, across every tax that applies, as Money"
          },
          "total_discount": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_Money"
              }
            ],
            "description": "Every discount together — the member discount plus the pay-in-full one — as Money"
          },
          "member_discount": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_Money"
              }
            ],
            "description": "The discount the vendor set on the invoice, as Money"
          },
          "pay_in_full_discount": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_Money"
              }
            ],
            "description": "The extra discount for paying the whole invoice at once, as Money"
          },
          "total_price": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_Money"
              }
            ],
            "description": "What the client owes: line items, less discounts, plus tax and service charges, as Money"
          },
          "invoice_type": {
            "type": "string",
            "enum": [
              "payment_schedule",
              "recurring"
            ],
            "description": "Whether the client pays on a schedule of installments or on a repeating cycle"
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes"
        ]
      },
      "Api_V3_Entities_Money": {
        "type": "object",
        "properties": {
          "amount": {
            "type": "integer",
            "format": "int32",
            "description": "Amount in minor units (cents). 1500 = $15.00."
          },
          "currency": {
            "type": "string",
            "description": "ISO-4217 currency code, lowercase (e.g. \"usd\")."
          }
        },
        "required": [
          "amount",
          "currency"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_InvoiceHeaderBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "invoice_header": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_InvoiceHeader"
              }
            ],
            "description": "Title, who bills, which project"
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes",
          "invoice_header"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_InvoiceHeader": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "description": "Heading shown above the invoice (defaults to \"INVOICE\")",
            "nullable": true
          },
          "bill_from_content": {
            "type": "object",
            "description": "Who is billing, snapshotted at publish: company_icon_url, is_default_company_icon, company_name, company_email, company_phone_number, and company_address (city, state, street_address, zip_code, country). Untyped — see above.",
            "nullable": true
          },
          "project_details": {
            "type": "object",
            "description": "What the invoice is for, snapshotted at publish: project_name, project_type, project_location, project_date. Untyped — see above.",
            "nullable": true
          }
        },
        "required": [
          "title",
          "bill_from_content",
          "project_details"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_InvoiceServiceItemBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "layout_type": {
            "type": "string",
            "enum": [
              "vertical",
              "horizontal"
            ],
            "description": "Whether this container stacks its children or lays them out side by side"
          },
          "composition_type": {
            "type": "string",
            "enum": [
              "default",
              "company_info"
            ],
            "description": "Which prebuilt composition this container is an instance of"
          },
          "children_layout": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_ChildLayout"
            },
            "description": "The blocks inside this container — each named by `block_id`, with how much room it gets and in what order. Look each one up in the file's `blocks`. Absent on blocks that cannot nest."
          },
          "container_title": {
            "type": "string",
            "description": "Vendor-facing label for the container in the builder"
          },
          "source_flow_id": {
            "type": "string",
            "description": "Id of the smart file this container was copied in from"
          },
          "background_image": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_Image"
              }
            ],
            "description": "Picture drawn behind the container"
          },
          "service_type": {
            "type": "string",
            "enum": [
              "service",
              "package"
            ],
            "description": "service for a standalone line item; package for one that groups sub-items as children",
            "nullable": true
          },
          "service_item": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_ServiceItem"
              }
            ],
            "description": "What the line item bills for"
          },
          "service_image": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_Image"
              }
            ],
            "description": "The line item's picture, when it has one",
            "nullable": true
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes",
          "service_type",
          "service_item",
          "service_image"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_ServiceItem": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "description": "Line item name",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Line item description, shown under the name",
            "nullable": true
          },
          "quantity": {
            "type": "number",
            "format": "float",
            "description": "How many units this line item bills for. Null means the member chose not to display a quantity for this line (e.g. \"consulting hours\" would set a real quantity, but \"consult meeting\" would leave it null) — pricing always treats a null quantity as a 1x multiplier of the unit price, same as an explicit 1.",
            "nullable": true
          },
          "price_per_unit": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_Money"
              }
            ],
            "description": "Price of a single unit as Money (integer cents); null when the item has no price",
            "nullable": true
          },
          "unit": {
            "type": "string",
            "description": "What one unit is, as typed by the member (e.g. \"hour\", \"Travel Rate\"); null means the default, item",
            "nullable": true
          }
        },
        "required": [
          "title",
          "description",
          "quantity",
          "price_per_unit",
          "unit"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_InvoiceSummaryBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "invoice_summary": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_InvoiceSummary"
              }
            ],
            "description": "Currency, taxes, discount, late fee and payment plan"
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes",
          "invoice_summary"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_InvoiceSummary": {
        "type": "object",
        "properties": {
          "currency": {
            "type": "string",
            "enum": [
              "AED",
              "AFN",
              "ALL",
              "AMD",
              "AOA",
              "ARS",
              "AUD",
              "AZN",
              "BAM",
              "BBD",
              "BDT",
              "BGN",
              "BHD",
              "BND",
              "BOB",
              "BSD",
              "BRL",
              "BWP",
              "BZD",
              "CAD",
              "CHF",
              "CLP",
              "CNY",
              "COP",
              "CRC",
              "CUP",
              "CZK",
              "DKK",
              "DOP",
              "DZD",
              "EGP",
              "ETB",
              "EUR",
              "FJD",
              "GBP",
              "GEL",
              "GHS",
              "GTQ",
              "GYD",
              "HKD",
              "HNL",
              "HTG",
              "HUF",
              "IDR",
              "ILS",
              "INR",
              "IQD",
              "IRR",
              "ISK",
              "JMD",
              "JOD",
              "JPY",
              "KES",
              "KGS",
              "KHR",
              "KRW",
              "KWD",
              "KZT",
              "LAK",
              "LBP",
              "LKR",
              "MAD",
              "MKD",
              "MMK",
              "MNT",
              "MOP",
              "MUR",
              "MXN",
              "MYR",
              "MZN",
              "NAD",
              "NGN",
              "NIO",
              "NOK",
              "NPR",
              "NZD",
              "OMR",
              "PAB",
              "PEN",
              "PGK",
              "PHP",
              "PKR",
              "PLN",
              "PYG",
              "QAR",
              "RON",
              "RSD",
              "RUB",
              "RWF",
              "SAR",
              "SEK",
              "SGD",
              "SRD",
              "SVC",
              "SYP",
              "THB",
              "TJS",
              "TMT",
              "TND",
              "TRY",
              "TTD",
              "TWD",
              "TZS",
              "UAH",
              "UGX",
              "USD",
              "UYU",
              "UZS",
              "VES",
              "VND",
              "XAF",
              "XOF",
              "XPF",
              "YER",
              "ZAR",
              "ZMW",
              "ZWL"
            ],
            "description": "ISO-4217 code of the currency the invoice is billed in: the file's, which follows the company currency"
          },
          "discount_percentage": {
            "type": "number",
            "format": "float",
            "description": "Discount taken off the subtotal as a percentage of it; null when the discount is an amount",
            "nullable": true
          },
          "discount_amount": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_Money"
              }
            ],
            "description": "Discount taken off the subtotal as Money; null when the discount is a percentage",
            "nullable": true
          },
          "allow_promo_code": {
            "type": "boolean",
            "description": "Whether checkout shows a promo-code entry field. Lead forms only; absent means off",
            "nullable": true
          },
          "tax_1": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_InvoiceSummary_Tax"
              }
            ],
            "description": "First tax slot; null when the vendor has not set one",
            "nullable": true
          },
          "tax_2": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_InvoiceSummary_Tax"
              }
            ],
            "description": "Second tax slot; null when the vendor has not set one",
            "nullable": true
          },
          "tax_3": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_InvoiceSummary_Tax"
              }
            ],
            "description": "Third tax slot; null when the vendor has not set one",
            "nullable": true
          },
          "compound_tax_id": {
            "type": "string",
            "description": "The tax charged on top of the others rather than on the subtotal alone, if any",
            "nullable": true
          },
          "late_fee_percentage": {
            "type": "number",
            "format": "float",
            "description": "Percentage charged on an overdue payment when late_fee_enabled"
          },
          "late_fee_enabled": {
            "type": "boolean",
            "description": "Whether a late fee is charged on payments past their due date"
          },
          "is_client_payment_plan": {
            "type": "boolean",
            "description": "Whether the client chooses their own installment plan at checkout",
            "nullable": true
          },
          "client_payment_plan_config": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_InvoiceSummary_ClientPaymentPlanConfig"
              }
            ],
            "description": "Bounds on the plan the client may choose, when is_client_payment_plan"
          },
          "service_charges": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_InvoiceSummary_ServiceCharge"
            },
            "description": "Service charges applied to the invoice",
            "nullable": true
          }
        },
        "required": [
          "currency",
          "discount_percentage",
          "discount_amount",
          "allow_promo_code",
          "tax_1",
          "tax_2",
          "tax_3",
          "compound_tax_id",
          "late_fee_percentage",
          "late_fee_enabled",
          "is_client_payment_plan",
          "client_payment_plan_config",
          "service_charges"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_InvoiceSummary_Tax": {
        "type": "object",
        "properties": {
          "tax_id": {
            "type": "string",
            "description": "Id of this tax, as service charges reference it",
            "nullable": true
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether this tax is actually charged"
          },
          "percentage": {
            "type": "number",
            "format": "float",
            "description": "The tax as a percentage of what it is charged on; null when it is an amount",
            "nullable": true
          },
          "amount": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_Money"
              }
            ],
            "description": "The tax as a fixed amount, as Money; null when it is a percentage",
            "nullable": true
          },
          "label": {
            "type": "string",
            "description": "What this tax is called on the invoice",
            "nullable": true
          },
          "is_custom_tax_label": {
            "type": "boolean",
            "description": "Whether the vendor wrote the label themselves; when false it is a default the client may show translated for the company country",
            "nullable": true
          }
        },
        "required": [
          "tax_id",
          "is_active",
          "percentage",
          "amount",
          "label",
          "is_custom_tax_label"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_InvoiceSummary_ClientPaymentPlanConfig": {
        "type": "object",
        "properties": {
          "max_number_of_payments": {
            "type": "integer",
            "format": "int32",
            "description": "Most installments the client may split into",
            "nullable": true
          },
          "first_payment_due_date": {
            "type": "string",
            "format": "date",
            "description": "The first installment's due date, used when first_payment_due_date_type is fixed",
            "nullable": true
          },
          "first_payment_due_date_type": {
            "type": "string",
            "enum": [
              "date_sent",
              "fixed",
              "smart_date",
              "midway",
              "project_date",
              "milestone",
              "today",
              "on_session_date",
              "before_session_date"
            ],
            "description": "When the client's first installment is due: date_sent for the day the file is sent, fixed for a date set in first_payment_due_date",
            "nullable": true
          },
          "allow_pay_in_full_discount": {
            "type": "boolean",
            "description": "Whether a client on a payment plan is offered a discount for paying in full instead",
            "nullable": true
          },
          "pay_in_full_discount_percentage": {
            "type": "number",
            "format": "float",
            "description": "The pay-in-full discount as a percentage; null when it is an amount",
            "nullable": true
          },
          "pay_in_full_discount_amount": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_Money"
              }
            ],
            "description": "The pay-in-full discount as Money; null when it is a percentage",
            "nullable": true
          }
        },
        "required": [
          "max_number_of_payments",
          "first_payment_due_date",
          "first_payment_due_date_type",
          "allow_pay_in_full_discount",
          "pay_in_full_discount_percentage",
          "pay_in_full_discount_amount"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_InvoiceSummary_ServiceCharge": {
        "type": "object",
        "properties": {
          "service_charge_id": {
            "type": "string",
            "description": "Id of this service charge",
            "nullable": true
          },
          "percentage": {
            "type": "number",
            "format": "float",
            "description": "The charge as a percentage of the taxable base; null when it is an amount",
            "nullable": true
          },
          "amount": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_Money"
              }
            ],
            "description": "The charge as a fixed amount, as Money; null when it is a percentage",
            "nullable": true
          },
          "label": {
            "type": "string",
            "description": "What this charge is called on the invoice",
            "nullable": true
          },
          "applied_taxes_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The taxes this charge is itself taxed by"
          }
        },
        "required": [
          "service_charge_id",
          "percentage",
          "amount",
          "label",
          "applied_taxes_ids"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_LeadDetailsBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "layout_type": {
            "type": "string",
            "enum": [
              "vertical",
              "horizontal"
            ],
            "description": "Whether this container stacks its children or lays them out side by side"
          },
          "composition_type": {
            "type": "string",
            "enum": [
              "default",
              "company_info"
            ],
            "description": "Which prebuilt composition this container is an instance of"
          },
          "children_layout": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_ChildLayout"
            },
            "description": "The blocks inside this container — each named by `block_id`, with how much room it gets and in what order. Look each one up in the file's `blocks`. Absent on blocks that cannot nest."
          },
          "container_title": {
            "type": "string",
            "description": "Vendor-facing label for the container in the builder"
          },
          "source_flow_id": {
            "type": "string",
            "description": "Id of the smart file this container was copied in from"
          },
          "background_image": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_Image"
              }
            ],
            "description": "Picture drawn behind the container"
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_PaymentBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "date_issued": {
            "type": "string",
            "format": "date-time",
            "description": "When the payment was created",
            "nullable": true
          },
          "payment_content": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_PaymentContent"
              }
            ],
            "description": "How much it bills and when it falls due"
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes",
          "date_issued",
          "payment_content"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_PaymentContent": {
        "type": "object",
        "properties": {
          "date_calc_type": {
            "type": "string",
            "enum": [
              "date_sent",
              "fixed",
              "smart_date",
              "midway",
              "project_date",
              "milestone",
              "today",
              "on_session_date",
              "before_session_date"
            ],
            "description": "When the installment falls due: date_sent, project_date, midway, fixed, smart_date, milestone, on_session_date, or before_session_date"
          },
          "smart_date_period": {
            "type": "integer",
            "format": "int32",
            "description": "How many periods away the due date is, when date_calc_type is smart_date; how many days before the booked session, when it is before_session_date",
            "nullable": true
          },
          "smart_date_period_type": {
            "type": "string",
            "enum": [
              "day",
              "month",
              "year",
              "week"
            ],
            "description": "The period smart_date_period counts in",
            "nullable": true
          },
          "smart_date_period_relation": {
            "type": "string",
            "enum": [
              "before_project",
              "after_project",
              "after_sent",
              "after_previous_charge"
            ],
            "description": "What the period counts from: after_sent, before_project or after_project",
            "nullable": true
          },
          "fixed_date": {
            "type": "string",
            "format": "date",
            "description": "The due date, when date_calc_type is fixed",
            "nullable": true
          },
          "milestone_title": {
            "type": "string",
            "description": "The milestone that makes the installment due, when date_calc_type is milestone",
            "nullable": true
          },
          "amount_calc_type": {
            "type": "string",
            "enum": [
              "fixed",
              "percentage",
              "divide_equally"
            ],
            "description": "How the amount is derived: divide_equally (an equal share of the total), percentage, or fixed"
          },
          "fixed_amount": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_Money"
              }
            ],
            "description": "The installment amount as Money (integer cents), when amount_calc_type is fixed",
            "nullable": true
          },
          "percentage": {
            "type": "number",
            "format": "float",
            "description": "Share of the invoice total this installment bills, when amount_calc_type is percentage",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Installment label as the client sees it",
            "nullable": true
          }
        },
        "required": [
          "date_calc_type",
          "smart_date_period",
          "smart_date_period_type",
          "smart_date_period_relation",
          "fixed_date",
          "milestone_title",
          "amount_calc_type",
          "fixed_amount",
          "percentage",
          "description"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_PaymentScheduleBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "layout_type": {
            "type": "string",
            "enum": [
              "vertical",
              "horizontal"
            ],
            "description": "Whether this container stacks its children or lays them out side by side"
          },
          "composition_type": {
            "type": "string",
            "enum": [
              "default",
              "company_info"
            ],
            "description": "Which prebuilt composition this container is an instance of"
          },
          "children_layout": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_ChildLayout"
            },
            "description": "The blocks inside this container — each named by `block_id`, with how much room it gets and in what order. Look each one up in the file's `blocks`. Absent on blocks that cannot nest."
          },
          "container_title": {
            "type": "string",
            "description": "Vendor-facing label for the container in the builder"
          },
          "source_flow_id": {
            "type": "string",
            "description": "Id of the smart file this container was copied in from"
          },
          "background_image": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_Image"
              }
            ],
            "description": "Picture drawn behind the container"
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_QuestionBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "question": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_Question"
              }
            ],
            "description": "The question"
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes",
          "question"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_Question": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique identifier for this question",
            "nullable": true
          },
          "question_type": {
            "type": "string",
            "enum": [
              "textbox",
              "open_question",
              "dropdown",
              "radio",
              "checkbox",
              "textarea",
              "date_picker",
              "upload_attachments",
              "number",
              "url",
              "table"
            ],
            "description": "Kind of question",
            "nullable": true
          },
          "text": {
            "type": "string",
            "description": "The question as the client sees it",
            "nullable": true
          },
          "description": {
            "type": "string",
            "description": "Longer detail about the question",
            "nullable": true
          },
          "placeholder": {
            "type": "string",
            "description": "Placeholder shown in the empty answer field",
            "nullable": true
          },
          "is_deletable": {
            "type": "boolean",
            "description": "Whether a member can remove this question from the flow",
            "nullable": true
          },
          "is_required": {
            "type": "boolean",
            "description": "Whether the client must answer this question",
            "nullable": true
          },
          "validation_type": {
            "type": "string",
            "enum": [
              "email",
              "number",
              "url"
            ],
            "description": "Type of validation to apply to the answer",
            "nullable": true
          },
          "order": {
            "type": "integer",
            "format": "int32",
            "description": "Display order of this question relative to others on the page",
            "nullable": true
          },
          "connected_property": {
            "type": "string",
            "description": "Smart field or data property this question is linked to",
            "nullable": true
          },
          "data_key": {
            "type": "string",
            "description": "Key used to store the answer in the submission data",
            "nullable": true
          },
          "has_end_date": {
            "type": "boolean",
            "description": "Whether a date question asks for a range rather than a single date",
            "nullable": true
          },
          "has_time": {
            "type": "boolean",
            "description": "Whether a date question asks for a time alongside the date",
            "nullable": true
          },
          "min_years_ago": {
            "type": "integer",
            "format": "int32",
            "description": "How many years back the answered date must be at least (date questions only); null when unrestricted",
            "nullable": true
          },
          "start_date_text": {
            "type": "string",
            "description": "Label for the start date field",
            "nullable": true
          },
          "start_time_text": {
            "type": "string",
            "description": "Label for the start time field",
            "nullable": true
          },
          "end_date_text": {
            "type": "string",
            "description": "Label for the end date field",
            "nullable": true
          },
          "end_time_text": {
            "type": "string",
            "description": "Label for the end time field",
            "nullable": true
          },
          "options": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_Question_Option"
            },
            "description": "Selectable answers of a choice question, in the order the client sees them"
          },
          "columns": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_Question_Column"
            },
            "description": "Columns of a table question, in display order"
          }
        },
        "required": [
          "id",
          "question_type",
          "text",
          "description",
          "placeholder",
          "is_deletable",
          "is_required",
          "validation_type",
          "order",
          "connected_property",
          "data_key"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_Question_Option": {
        "type": "object",
        "properties": {
          "answer_text": {
            "type": "string",
            "description": "The answer as the client sees it",
            "nullable": true
          }
        },
        "required": [
          "answer_text"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_Question_Column": {
        "type": "object",
        "properties": {
          "column_id": {
            "type": "string",
            "description": "Identifier for this column",
            "nullable": true
          },
          "label": {
            "type": "string",
            "description": "Column header label as the client sees it",
            "nullable": true
          },
          "width": {
            "type": "integer",
            "format": "int32",
            "description": "Column width in pixels",
            "nullable": true
          },
          "order": {
            "type": "integer",
            "format": "int32",
            "description": "Display order of this column",
            "nullable": true
          }
        },
        "required": [
          "column_id",
          "label",
          "width",
          "order"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_RecurringScheduleBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "layout_type": {
            "type": "string",
            "enum": [
              "vertical",
              "horizontal"
            ],
            "description": "Whether this container stacks its children or lays them out side by side"
          },
          "composition_type": {
            "type": "string",
            "enum": [
              "default",
              "company_info"
            ],
            "description": "Which prebuilt composition this container is an instance of"
          },
          "children_layout": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_ChildLayout"
            },
            "description": "The blocks inside this container — each named by `block_id`, with how much room it gets and in what order. Look each one up in the file's `blocks`. Absent on blocks that cannot nest."
          },
          "container_title": {
            "type": "string",
            "description": "Vendor-facing label for the container in the builder"
          },
          "source_flow_id": {
            "type": "string",
            "description": "Id of the smart file this container was copied in from"
          },
          "background_image": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_Image"
              }
            ],
            "description": "Picture drawn behind the container"
          },
          "recurring_schedule": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_RecurringSchedule"
              }
            ],
            "description": "The payment schedule configuration"
          },
          "sent_invoices_count": {
            "type": "integer",
            "format": "int32",
            "description": "How many invoices this schedule has already sent",
            "nullable": true
          },
          "upcoming_invoices_count": {
            "type": "integer",
            "format": "int32",
            "description": "How many are still to come; null when the schedule never ends",
            "nullable": true
          },
          "total_paid_amount": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_Money"
              }
            ],
            "description": "What the client has paid so far, as Money",
            "nullable": true
          },
          "paid_payments_count": {
            "type": "integer",
            "format": "int32",
            "description": "How many of the invoices have been paid",
            "nullable": true
          },
          "last_invoice_date": {
            "type": "string",
            "format": "date",
            "description": "When the final invoice falls; null when the schedule never ends",
            "nullable": true
          },
          "upcoming_invoices": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_UpcomingInvoice"
            },
            "description": "The next invoices the schedule will raise, up to ten ahead",
            "nullable": true
          },
          "upcoming_invoice_due_date": {
            "type": "string",
            "format": "date",
            "description": "When the next unpaid invoice comes due",
            "nullable": true
          },
          "min_valid_due_date": {
            "type": "string",
            "format": "date",
            "description": "The earliest date an unpaid invoice may be moved to",
            "nullable": true
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes",
          "recurring_schedule"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_RecurringSchedule": {
        "type": "object",
        "properties": {
          "repetition_unit_type": {
            "type": "string",
            "enum": [
              "daily",
              "weekly",
              "monthly",
              "yearly",
              "custom"
            ],
            "description": "Payment frequency: daily, weekly, monthly, yearly, or custom"
          },
          "custom_unit_count": {
            "type": "integer",
            "format": "int32",
            "description": "For custom repetitions, how many units between payments",
            "nullable": true
          },
          "custom_unit_type": {
            "type": "string",
            "enum": [
              "days",
              "weeks",
              "months",
              "years"
            ],
            "description": "For custom repetitions, the unit: days, weeks, months, or years",
            "nullable": true
          },
          "month_of_year": {
            "type": "string",
            "enum": [
              "January",
              "February",
              "March",
              "April",
              "May",
              "June",
              "July",
              "August",
              "September",
              "October",
              "November",
              "December"
            ],
            "description": "For yearly repetitions, the month of the payment",
            "nullable": true
          },
          "day_of_month": {
            "type": "integer",
            "format": "int32",
            "description": "For monthly/yearly repetitions, the day of the month",
            "nullable": true
          },
          "day_of_week": {
            "type": "string",
            "enum": [
              "Sunday",
              "Monday",
              "Tuesday",
              "Wednesday",
              "Thursday",
              "Friday",
              "Saturday"
            ],
            "description": "For weekly repetitions, the day of the week",
            "nullable": true
          },
          "first_invoice_due_date": {
            "type": "string",
            "format": "date",
            "description": "The date the first payment is due",
            "nullable": true
          },
          "end_type": {
            "type": "string",
            "enum": [
              "never",
              "fixed_date",
              "repetition_count"
            ],
            "description": "How the schedule ends: never (indefinitely), fixed_date (on a specific date), or repetition_count (after N payments)"
          },
          "repetition_count": {
            "type": "integer",
            "format": "int32",
            "description": "For repetition_count end_type, the total number of payments",
            "nullable": true
          },
          "end_date": {
            "type": "string",
            "format": "date",
            "description": "For fixed_date end_type, the date of the final payment",
            "nullable": true
          }
        },
        "required": [
          "repetition_unit_type",
          "custom_unit_count",
          "custom_unit_type",
          "month_of_year",
          "day_of_month",
          "day_of_week",
          "first_invoice_due_date",
          "end_type",
          "repetition_count",
          "end_date"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_UpcomingInvoice": {
        "type": "object",
        "properties": {
          "flow_id": {
            "type": "string",
            "description": "The smart file this invoice will be billed against",
            "nullable": true
          },
          "due_date": {
            "type": "string",
            "format": "date",
            "description": "When this one comes due",
            "nullable": true
          },
          "amount": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_Money"
              }
            ],
            "description": "What it will charge, as Money",
            "nullable": true
          }
        },
        "required": [
          "flow_id",
          "due_date",
          "amount"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_ScheduleContainerBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "layout_type": {
            "type": "string",
            "enum": [
              "vertical",
              "horizontal"
            ],
            "description": "Whether this container stacks its children or lays them out side by side"
          },
          "composition_type": {
            "type": "string",
            "enum": [
              "default",
              "company_info"
            ],
            "description": "Which prebuilt composition this container is an instance of"
          },
          "children_layout": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_ChildLayout"
            },
            "description": "The blocks inside this container — each named by `block_id`, with how much room it gets and in what order. Look each one up in the file's `blocks`. Absent on blocks that cannot nest."
          },
          "container_title": {
            "type": "string",
            "description": "Vendor-facing label for the container in the builder"
          },
          "source_flow_id": {
            "type": "string",
            "description": "Id of the smart file this container was copied in from"
          },
          "background_image": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_Image"
              }
            ],
            "description": "Picture drawn behind the container"
          },
          "schedule_session_trigger": {
            "type": "string",
            "enum": [
              "immediately",
              "once_invoice_paid",
              "once_contract_signed",
              "once_signed_and_paid"
            ],
            "description": "When a session is booked from this block: immediately or after_payment"
          },
          "is_required": {
            "type": "boolean",
            "description": "Whether the client must book a session to complete the flow"
          },
          "session_config_id": {
            "type": "string",
            "description": "Id of the session config this block books from",
            "nullable": true
          },
          "session_config": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_SessionConfig"
              }
            ],
            "description": "Session configuration details (when session_config_id is set)",
            "nullable": true
          },
          "session_config_hash": {
            "type": "string",
            "description": "Digest of the session config (used to detect configuration changes)",
            "nullable": true
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes",
          "schedule_session_trigger",
          "is_required",
          "session_config_id",
          "session_config",
          "session_config_hash"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_SessionConfig": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Session config id (BSON ObjectId hex)",
            "nullable": true
          },
          "session_name": {
            "type": "string",
            "description": "Session name as shown to clients",
            "nullable": true
          },
          "session_type": {
            "type": "string",
            "enum": [
              "meeting",
              "in_person",
              "phone_call",
              "video_call",
              "personal",
              "other"
            ],
            "description": "Session kind: phone, video, in_person, or other",
            "nullable": true
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether clients can currently book this session",
            "nullable": true
          },
          "session_description": {
            "type": "string",
            "description": "Session description",
            "nullable": true
          },
          "session_timezone": {
            "type": "string",
            "description": "IANA timezone for session bookings",
            "nullable": true
          },
          "session_color": {
            "type": "string",
            "description": "Session color (hex like #abc123 or a named token like purple-shade-3)",
            "nullable": true
          },
          "allow_rescheduling": {
            "type": "boolean",
            "description": "Whether clients can reschedule a booked session",
            "nullable": true
          },
          "allow_canceling": {
            "type": "boolean",
            "description": "Whether clients can cancel a booked session",
            "nullable": true
          },
          "send_confirmation_email": {
            "type": "boolean",
            "description": "Whether a confirmation email is sent after booking",
            "nullable": true
          },
          "schedule_behaviour_type": {
            "type": "string",
            "enum": [
              "all",
              "single"
            ],
            "description": "Booking availability model: open, application, or appointment_request",
            "nullable": true
          },
          "window_type": {
            "type": "string",
            "enum": [
              "indefinitely",
              "rolling_window",
              "fixed_date_range"
            ],
            "description": "Booking window model: rolling (available up to N days out) or fixed",
            "nullable": true
          },
          "meeting_location": {
            "type": "string",
            "description": "Physical location (for in-person sessions)",
            "nullable": true
          },
          "video_meeting_link": {
            "type": "string",
            "description": "Video conferencing link (for video sessions)",
            "nullable": true
          },
          "phone_call_number": {
            "type": "string",
            "description": "Phone number (for phone call sessions)",
            "nullable": true
          },
          "phone_call_caller": {
            "type": "string",
            "enum": [
              "me",
              "client"
            ],
            "description": "Who places the call: client_calls, vendor_calls",
            "nullable": true
          },
          "confirmation_message": {
            "type": "string",
            "description": "Message shown to clients after they book",
            "nullable": true
          },
          "fixed_start_date": {
            "type": "string",
            "format": "date",
            "description": "Session start date (when window_type is fixed)",
            "nullable": true
          },
          "fixed_end_date": {
            "type": "string",
            "format": "date",
            "description": "Session end date (when window_type is fixed)",
            "nullable": true
          },
          "availability_increments": {
            "type": "integer",
            "format": "int32",
            "description": "Client can choose available time slots in increments of N minutes",
            "nullable": true
          },
          "video_conference_type": {
            "type": "string",
            "enum": [
              "google",
              "zoom",
              "other"
            ],
            "description": "Video platform: zoom, meets, teams, or other",
            "nullable": true
          },
          "session_duration": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_SessionConfig_Duration"
              }
            ],
            "description": "How long each session lasts",
            "nullable": true
          },
          "rolling_window_duration": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_SessionConfig_Duration"
              }
            ],
            "description": "Booking window: how far in advance can clients book (when window_type is rolling)",
            "nullable": true
          },
          "buffer_before": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_SessionConfig_Duration"
              }
            ],
            "description": "Time to block before each session",
            "nullable": true
          },
          "buffer_after": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_SessionConfig_Duration"
              }
            ],
            "description": "Time to block after each session",
            "nullable": true
          },
          "notice_period": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_SessionConfig_Duration"
              }
            ],
            "description": "How far in advance clients must book before the session",
            "nullable": true
          },
          "session_reminders": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_SessionConfig_SessionReminder"
            },
            "description": "Reminders sent before the session"
          },
          "max_clients": {
            "type": "integer",
            "format": "int32",
            "description": "How many clients can book this session simultaneously",
            "nullable": true
          },
          "show_available_seats_enabled": {
            "type": "boolean",
            "description": "Whether to show clients how many seats remain",
            "nullable": true
          },
          "set_as_project_date": {
            "type": "boolean",
            "description": "Whether the booked session becomes the project date",
            "nullable": true
          },
          "show_project_as_calendar_entry": {
            "type": "boolean",
            "description": "Whether the project the booking dates also appears as its own calendar entry",
            "nullable": true
          },
          "user_id": {
            "type": "string",
            "description": "User id of the session owner (vendor)",
            "nullable": true
          },
          "shared_member_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "User ids who can see and manage this session config",
            "nullable": true
          },
          "co_host_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "User ids designated as co-hosts (vendor team members who share bookings)",
            "nullable": true
          },
          "notification_recipient_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "User ids who receive booking notifications",
            "nullable": true
          },
          "shared_members": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_UserSummary"
            },
            "description": "Users who can see and manage this session config (resolved from shared_member_ids)",
            "nullable": true
          },
          "session_url": {
            "type": "string",
            "description": "Booking link where clients can select and book a session",
            "nullable": true
          },
          "placement_id": {
            "type": "string",
            "description": "Website placement id (for tracking where the session was booked from)",
            "nullable": true
          },
          "config_hash": {
            "type": "string",
            "description": "MD5 digest of relevant config fields (used to detect changes)",
            "nullable": true
          }
        },
        "required": [
          "id",
          "session_name",
          "session_type",
          "enabled",
          "session_description",
          "session_timezone",
          "session_color",
          "allow_rescheduling",
          "allow_canceling",
          "send_confirmation_email",
          "schedule_behaviour_type",
          "window_type",
          "meeting_location",
          "video_meeting_link",
          "phone_call_number",
          "phone_call_caller",
          "confirmation_message",
          "fixed_start_date",
          "fixed_end_date",
          "availability_increments",
          "video_conference_type",
          "session_duration",
          "rolling_window_duration",
          "buffer_before",
          "buffer_after",
          "notice_period",
          "session_reminders",
          "max_clients",
          "show_available_seats_enabled",
          "set_as_project_date",
          "show_project_as_calendar_entry",
          "user_id",
          "shared_member_ids",
          "co_host_ids",
          "notification_recipient_ids",
          "shared_members",
          "session_url",
          "placement_id",
          "config_hash"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_SessionConfig_Duration": {
        "type": "object",
        "properties": {
          "unit_count": {
            "type": "integer",
            "format": "int32",
            "description": "How many units of time",
            "nullable": true
          },
          "unit_type": {
            "type": "string",
            "enum": [
              "seconds",
              "minutes",
              "hours",
              "days",
              "weeks",
              "months",
              "years"
            ],
            "description": "The unit: minutes, hours, days, weeks, months, or years",
            "nullable": true
          }
        },
        "required": [
          "unit_count",
          "unit_type"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_SessionConfig_SessionReminder": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Reminder id (BSON ObjectId hex)",
            "nullable": true
          },
          "reminder_type": {
            "type": "string",
            "enum": [
              "sms",
              "email",
              "sms_and_email"
            ],
            "description": "How the reminder is delivered: email or in-app",
            "nullable": true
          },
          "reminder_title": {
            "type": "string",
            "description": "Reminder heading",
            "nullable": true
          },
          "reminder_message": {
            "type": "string",
            "description": "Reminder body",
            "nullable": true
          },
          "notify_me": {
            "type": "boolean",
            "description": "Whether the reminder is sent to the session owner (vendor) as well",
            "nullable": true
          },
          "when": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_SessionConfig_Duration"
              }
            ],
            "description": "How long before the session this reminder fires",
            "nullable": true
          }
        },
        "required": [
          "id",
          "reminder_type",
          "reminder_title",
          "reminder_message",
          "notify_me",
          "when"
        ]
      },
      "Api_V3_Entities_UserSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "User id (BSON ObjectId hex)"
          },
          "first_name": {
            "type": "string",
            "description": "First name",
            "nullable": true
          },
          "last_name": {
            "type": "string",
            "description": "Last name",
            "nullable": true
          },
          "full_name": {
            "type": "string",
            "description": "Full display name",
            "nullable": true
          },
          "email": {
            "type": "string",
            "description": "Email address",
            "nullable": true
          },
          "phone_number": {
            "type": "string",
            "description": "Phone number",
            "nullable": true
          },
          "address": {
            "type": "string",
            "description": "Postal address, as one string",
            "nullable": true
          },
          "job_title": {
            "type": "string",
            "description": "Role at their company",
            "nullable": true
          },
          "avatar_url": {
            "type": "string",
            "description": "Profile image URL",
            "nullable": true
          },
          "kind": {
            "type": "string",
            "description": "What kind of person this is (lowercase snake_case enum: client, vendor, both, other, malkut, admin, external). Distinct from a WorkspaceMember's `kind`, which only answers client-vs-vendor for one membership row; this is the person's own type.",
            "nullable": true
          },
          "company": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_CompanySummary"
              }
            ],
            "description": "The business this person belongs to (null for a person with no company)",
            "nullable": true
          }
        },
        "required": [
          "id",
          "first_name",
          "last_name",
          "full_name",
          "email",
          "phone_number",
          "address",
          "job_title",
          "avatar_url",
          "kind",
          "company"
        ]
      },
      "Api_V3_Entities_CompanySummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "objectid",
            "description": "Company id"
          },
          "name": {
            "type": "string",
            "description": "Business name",
            "nullable": true
          },
          "type_name": {
            "type": "string",
            "description": "Human-readable company type (display string, resolved server-side)",
            "nullable": true
          },
          "logo_url": {
            "type": "string",
            "description": "Business logo URL; null when none is set",
            "nullable": true
          }
        },
        "required": [
          "id",
          "name",
          "type_name",
          "logo_url"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_ScheduleSessionBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_SecurityDepositBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_ServiceItemBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "layout_type": {
            "type": "string",
            "enum": [
              "vertical",
              "horizontal"
            ],
            "description": "Whether this container stacks its children or lays them out side by side"
          },
          "composition_type": {
            "type": "string",
            "enum": [
              "default",
              "company_info"
            ],
            "description": "Which prebuilt composition this container is an instance of"
          },
          "children_layout": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_ChildLayout"
            },
            "description": "The blocks inside this container — each named by `block_id`, with how much room it gets and in what order. Look each one up in the file's `blocks`. Absent on blocks that cannot nest."
          },
          "container_title": {
            "type": "string",
            "description": "Vendor-facing label for the container in the builder"
          },
          "source_flow_id": {
            "type": "string",
            "description": "Id of the smart file this container was copied in from"
          },
          "background_image": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_Image"
              }
            ],
            "description": "Picture drawn behind the container"
          },
          "service_type": {
            "type": "string",
            "enum": [
              "service",
              "package"
            ],
            "description": "service for a standalone line item; package for one that groups sub-items as children",
            "nullable": true
          },
          "service_item": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_ServiceItem"
              }
            ],
            "description": "What the line item bills for"
          },
          "service_image": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_Image"
              }
            ],
            "description": "The line item's picture, when it has one",
            "nullable": true
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes",
          "service_type",
          "service_item",
          "service_image"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_ServiceItemsContainerBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "layout_type": {
            "type": "string",
            "enum": [
              "vertical",
              "horizontal"
            ],
            "description": "Whether this container stacks its children or lays them out side by side"
          },
          "composition_type": {
            "type": "string",
            "enum": [
              "default",
              "company_info"
            ],
            "description": "Which prebuilt composition this container is an instance of"
          },
          "children_layout": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_ChildLayout"
            },
            "description": "The blocks inside this container — each named by `block_id`, with how much room it gets and in what order. Look each one up in the file's `blocks`. Absent on blocks that cannot nest."
          },
          "container_title": {
            "type": "string",
            "description": "Vendor-facing label for the container in the builder"
          },
          "source_flow_id": {
            "type": "string",
            "description": "Id of the smart file this container was copied in from"
          },
          "background_image": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_Image"
              }
            ],
            "description": "Picture drawn behind the container"
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_ServiceSelectionBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "layout_type": {
            "type": "string",
            "enum": [
              "vertical",
              "horizontal"
            ],
            "description": "Whether this container stacks its children or lays them out side by side"
          },
          "composition_type": {
            "type": "string",
            "enum": [
              "default",
              "company_info"
            ],
            "description": "Which prebuilt composition this container is an instance of"
          },
          "children_layout": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_ChildLayout"
            },
            "description": "The blocks inside this container — each named by `block_id`, with how much room it gets and in what order. Look each one up in the file's `blocks`. Absent on blocks that cannot nest."
          },
          "container_title": {
            "type": "string",
            "description": "Vendor-facing label for the container in the builder"
          },
          "source_flow_id": {
            "type": "string",
            "description": "Id of the smart file this container was copied in from"
          },
          "background_image": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_Image"
              }
            ],
            "description": "Picture drawn behind the container"
          },
          "banner_text": {
            "type": "string",
            "description": "Text above the selection, as sanitized HTML",
            "nullable": true
          },
          "selection_required": {
            "type": "boolean",
            "description": "Whether the client must pick a service before submitting",
            "nullable": true
          },
          "send_info_to_invoice": {
            "type": "boolean",
            "description": "Whether the client's selection flows into the file's invoice",
            "nullable": true
          },
          "selection_type": {
            "type": "string",
            "enum": [
              "one",
              "multiple",
              "no_selection"
            ],
            "description": "How many services the client may pick: one, multiple, or no_selection (display only)",
            "nullable": true
          },
          "show_total": {
            "type": "boolean",
            "description": "Whether to display the total price of selected services",
            "nullable": true
          },
          "discount": {
            "type": "boolean",
            "description": "Whether discount calculation is enabled for this selection",
            "nullable": true
          },
          "services_layout": {
            "type": "string",
            "enum": [
              "rows",
              "two_columns",
              "three_columns"
            ],
            "description": "How the selectable services are laid out",
            "nullable": true
          },
          "invoice_block_id": {
            "type": "string",
            "description": "Id of the invoice block this selection writes to, if any",
            "nullable": true
          },
          "service_selection_type": {
            "type": "string",
            "enum": [
              "service",
              "session"
            ],
            "description": "Whether this selection is client-chosen or auto-selected by session type",
            "nullable": true
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes",
          "banner_text",
          "selection_required",
          "send_info_to_invoice",
          "selection_type",
          "show_total",
          "discount",
          "services_layout",
          "invoice_block_id",
          "service_selection_type"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_ServiceSelectionItemBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "layout_type": {
            "type": "string",
            "enum": [
              "vertical",
              "horizontal"
            ],
            "description": "Whether this container stacks its children or lays them out side by side"
          },
          "composition_type": {
            "type": "string",
            "enum": [
              "default",
              "company_info"
            ],
            "description": "Which prebuilt composition this container is an instance of"
          },
          "children_layout": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_ChildLayout"
            },
            "description": "The blocks inside this container — each named by `block_id`, with how much room it gets and in what order. Look each one up in the file's `blocks`. Absent on blocks that cannot nest."
          },
          "container_title": {
            "type": "string",
            "description": "Vendor-facing label for the container in the builder"
          },
          "source_flow_id": {
            "type": "string",
            "description": "Id of the smart file this container was copied in from"
          },
          "background_image": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_Image"
              }
            ],
            "description": "Picture drawn behind the container"
          },
          "service_type": {
            "type": "string",
            "enum": [
              "service",
              "package"
            ],
            "description": "service for a standalone line item; package for one that groups sub-items as children",
            "nullable": true
          },
          "service_item": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_ServiceItem"
              }
            ],
            "description": "What the line item bills for"
          },
          "service_image": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_Image"
              }
            ],
            "description": "The line item's picture, when it has one",
            "nullable": true
          },
          "invoice_service_item": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_ServiceItem"
              }
            ],
            "description": "What the item bills for when selected",
            "nullable": true
          },
          "allow_custom_quantity": {
            "type": "boolean",
            "description": "Whether the client may choose how many of this they want",
            "nullable": true
          },
          "min_quantity": {
            "type": "number",
            "format": "float",
            "description": "Fewest the client may choose",
            "nullable": true
          },
          "max_quantity": {
            "type": "number",
            "format": "float",
            "description": "Most the client may choose",
            "nullable": true
          },
          "session_config_id": {
            "type": "string",
            "description": "The bookable session type this item sells, if it sells one",
            "nullable": true
          },
          "session_config_hash": {
            "type": "string",
            "description": "Digest of the session config (used to detect configuration changes)",
            "nullable": true
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes",
          "service_type",
          "service_item",
          "service_image",
          "invoice_service_item",
          "allow_custom_quantity",
          "min_quantity",
          "max_quantity",
          "session_config_id",
          "session_config_hash"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_ServicesBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "layout_type": {
            "type": "string",
            "enum": [
              "vertical",
              "horizontal"
            ],
            "description": "Whether this container stacks its children or lays them out side by side"
          },
          "composition_type": {
            "type": "string",
            "enum": [
              "default",
              "company_info"
            ],
            "description": "Which prebuilt composition this container is an instance of"
          },
          "children_layout": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_ChildLayout"
            },
            "description": "The blocks inside this container — each named by `block_id`, with how much room it gets and in what order. Look each one up in the file's `blocks`. Absent on blocks that cannot nest."
          },
          "container_title": {
            "type": "string",
            "description": "Vendor-facing label for the container in the builder"
          },
          "source_flow_id": {
            "type": "string",
            "description": "Id of the smart file this container was copied in from"
          },
          "background_image": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_Image"
              }
            ],
            "description": "Picture drawn behind the container"
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_SignatureBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "signature": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_Signature"
              }
            ],
            "description": "Who is assigned to sign, and whether the signature is required"
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes",
          "signature"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_Signature": {
        "type": "object",
        "properties": {
          "signee_id": {
            "type": "string",
            "description": "Id of whoever is expected to sign; null until the slot is assigned",
            "nullable": true
          },
          "signee_name": {
            "type": "string",
            "description": "Name of the party expected to sign",
            "nullable": true
          },
          "signee_email": {
            "type": "string",
            "description": "Email address of the signee",
            "nullable": true
          },
          "signee_type": {
            "type": "string",
            "enum": [
              "couple_signature",
              "planner_signature",
              "vendor",
              "client"
            ],
            "description": "Which side of the file is signing here — the vendor, or the client",
            "nullable": true
          },
          "required": {
            "type": "boolean",
            "description": "Whether this signature is mandatory"
          },
          "signee_details": {
            "type": "string",
            "description": "Additional details about the signee",
            "nullable": true
          }
        },
        "required": [
          "signee_id",
          "signee_name",
          "signee_email",
          "signee_type",
          "required",
          "signee_details"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_SignaturesBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "layout_type": {
            "type": "string",
            "enum": [
              "vertical",
              "horizontal"
            ],
            "description": "Whether this container stacks its children or lays them out side by side"
          },
          "composition_type": {
            "type": "string",
            "enum": [
              "default",
              "company_info"
            ],
            "description": "Which prebuilt composition this container is an instance of"
          },
          "children_layout": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_ChildLayout"
            },
            "description": "The blocks inside this container — each named by `block_id`, with how much room it gets and in what order. Look each one up in the file's `blocks`. Absent on blocks that cannot nest."
          },
          "container_title": {
            "type": "string",
            "description": "Vendor-facing label for the container in the builder"
          },
          "source_flow_id": {
            "type": "string",
            "description": "Id of the smart file this container was copied in from"
          },
          "background_image": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_Image"
              }
            ],
            "description": "Picture drawn behind the container"
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_SocialBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_SpacerBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_TextBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "content": {
            "type": "string",
            "description": "The text, as sanitized HTML",
            "nullable": true
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes",
          "content"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_TimelineBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "layout_type": {
            "type": "string",
            "enum": [
              "vertical",
              "horizontal"
            ],
            "description": "Whether this container stacks its children or lays them out side by side"
          },
          "composition_type": {
            "type": "string",
            "enum": [
              "default",
              "company_info"
            ],
            "description": "Which prebuilt composition this container is an instance of"
          },
          "children_layout": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_ChildLayout"
            },
            "description": "The blocks inside this container — each named by `block_id`, with how much room it gets and in what order. Look each one up in the file's `blocks`. Absent on blocks that cannot nest."
          },
          "container_title": {
            "type": "string",
            "description": "Vendor-facing label for the container in the builder"
          },
          "source_flow_id": {
            "type": "string",
            "description": "Id of the smart file this container was copied in from"
          },
          "background_image": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_SmartFile_Block_Image"
              }
            ],
            "description": "Picture drawn behind the container"
          },
          "section_title": {
            "type": "string",
            "description": "Heading of the section"
          },
          "date": {
            "type": "string",
            "format": "date",
            "description": "Calendar date the section covers (no time of day)"
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_TimelineItemBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          },
          "start_time": {
            "type": "string",
            "description": "When the entry starts, as free text (e.g. \"4:00 PM\")"
          },
          "end_time": {
            "type": "string",
            "description": "When the entry ends, as free text"
          },
          "title": {
            "type": "string",
            "description": "What happens at this point in the timeline"
          },
          "note": {
            "type": "string",
            "description": "Longer detail under the entry, as sanitized HTML"
          },
          "location": {
            "type": "string",
            "description": "Where this part of the timeline happens"
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes"
        ]
      },
      "Api_V3_Entities_SmartFile_Block_VideoBlock": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Which kind of block this is, and therefore which variant schema its other fields follow. The block class name underscored (text_block, payment_block). Read from the model, so every node has one."
          },
          "block_id": {
            "type": "string",
            "description": "Stable block id (UUID) — what PATCH/DELETE content endpoints address."
          },
          "block_theme": {
            "type": "object",
            "description": "Presentation state for this block (colors, spacing, which columns show). Untyped: the underlying `styles` field accepts an arbitrary client-defined hash, so its keys are not ours to declare.",
            "nullable": true
          },
          "connected_variable_id": {
            "type": "string",
            "description": "Id of the variable holding this block's client-supplied value (an answer, a signature, a payment). Omitted entirely for blocks that own no variable."
          },
          "page_id": {
            "type": "string",
            "description": "Id of the page this block belongs to — how a flat `blocks` collection is split back into pages.",
            "nullable": true
          },
          "discarded": {
            "type": "boolean",
            "description": "Whether this block was dropped from the draft during a merge and is being shown only so the vendor can see what went. Never true on a published file."
          },
          "critical_changes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Why this block needs the client to re-approve it — empty when nothing does. A block earns an entry when a change to it invalidates something the client already agreed to, so entries only ever appear on a booked file. Always empty on templates."
          }
        },
        "required": [
          "type",
          "block_id",
          "page_id",
          "discarded",
          "critical_changes"
        ]
      },
      "Api_V3_Entities_CustomFieldValue_Date": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Api_V3_Entities_CustomFieldValue_Shared"
          },
          {
            "type": "object",
            "properties": {
              "value": {
                "type": "string",
                "format": "date",
                "description": "The calendar date held by this field (ISO8601, no time); null when unset",
                "nullable": true
              },
              "type": {
                "type": "string",
                "enum": [
                  "date"
                ],
                "description": "The field's value kind — the discriminator. One of: text, long_text, date, number, link, single_select, multi_select"
              }
            },
            "required": [
              "type",
              "value"
            ]
          }
        ]
      },
      "Api_V3_Entities_CustomFieldValue_Link": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Api_V3_Entities_CustomFieldValue_Shared"
          },
          {
            "type": "object",
            "properties": {
              "value": {
                "type": "string",
                "description": "The URL held by this field; null when unset. Not validated as a URL",
                "nullable": true
              },
              "type": {
                "type": "string",
                "enum": [
                  "link"
                ],
                "description": "The field's value kind — the discriminator. One of: text, long_text, date, number, link, single_select, multi_select"
              }
            },
            "required": [
              "type",
              "value"
            ]
          }
        ]
      },
      "Api_V3_Entities_CustomFieldValue_LongText": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Api_V3_Entities_CustomFieldValue_Shared"
          },
          {
            "type": "object",
            "properties": {
              "value": {
                "type": "string",
                "description": "The text held by this field; null when the member has not filled it in",
                "nullable": true
              },
              "type": {
                "type": "string",
                "enum": [
                  "long_text"
                ],
                "description": "The field's value kind — the discriminator. One of: text, long_text, date, number, link, single_select, multi_select"
              }
            },
            "required": [
              "type",
              "value"
            ]
          }
        ]
      },
      "Api_V3_Entities_CustomFieldValue_MultiSelect": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Api_V3_Entities_CustomFieldValue_Shared"
          },
          {
            "type": "object",
            "properties": {
              "value": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Api_V3_Entities_CustomFieldOption"
                },
                "description": "The selected options; `[]` when none. PATCH a comma-separated list of their `id`s to change them"
              },
              "type": {
                "type": "string",
                "enum": [
                  "multi_select"
                ],
                "description": "The field's value kind — the discriminator. One of: text, long_text, date, number, link, single_select, multi_select"
              }
            },
            "required": [
              "type",
              "value"
            ]
          }
        ]
      },
      "Api_V3_Entities_CustomFieldOption": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "objectid",
            "description": "Option id"
          },
          "label": {
            "type": "string",
            "description": "Option display label",
            "nullable": true
          },
          "color": {
            "type": "string",
            "description": "Option color (hex string, e.g. #EDE1D9)",
            "nullable": true
          }
        },
        "required": [
          "id",
          "label",
          "color"
        ]
      },
      "Api_V3_Entities_CustomFieldValue_Number": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Api_V3_Entities_CustomFieldValue_Shared"
          },
          {
            "type": "object",
            "properties": {
              "value": {
                "type": "number",
                "format": "float",
                "description": "The number held by this field; null when unset. A real `0` renders as 0",
                "nullable": true
              },
              "type": {
                "type": "string",
                "enum": [
                  "number"
                ],
                "description": "The field's value kind — the discriminator. One of: text, long_text, date, number, link, single_select, multi_select"
              }
            },
            "required": [
              "type",
              "value"
            ]
          }
        ]
      },
      "Api_V3_Entities_CustomFieldValue_SingleSelect": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Api_V3_Entities_CustomFieldValue_Shared"
          },
          {
            "type": "object",
            "properties": {
              "value": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/Api_V3_Entities_CustomFieldOption"
                  }
                ],
                "description": "The selected option; null when nothing is selected. PATCH its `id` to change it",
                "nullable": true
              },
              "type": {
                "type": "string",
                "enum": [
                  "single_select"
                ],
                "description": "The field's value kind — the discriminator. One of: text, long_text, date, number, link, single_select, multi_select"
              }
            },
            "required": [
              "type",
              "value"
            ]
          }
        ]
      },
      "Api_V3_Entities_CustomFieldValue_Text": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Api_V3_Entities_CustomFieldValue_Shared"
          },
          {
            "type": "object",
            "properties": {
              "value": {
                "type": "string",
                "description": "The text held by this field; null when the member has not filled it in",
                "nullable": true
              },
              "type": {
                "type": "string",
                "enum": [
                  "text"
                ],
                "description": "The field's value kind — the discriminator. One of: text, long_text, date, number, link, single_select, multi_select"
              }
            },
            "required": [
              "type",
              "value"
            ]
          }
        ]
      },
      "Api_V3_Entities_Conversation_Feed": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "feed",
              "unresolved_sms"
            ],
            "description": "The kind of conversation, the discriminator. One of: feed, unresolved_sms"
          },
          "id": {
            "type": "string",
            "description": "Conversation id — a BSON ObjectId hex string, UNLESS type is unresolved_sms, in which case it is an opaque synthetic sentinel"
          },
          "project_id": {
            "type": "string",
            "description": "Project (Event) id — null for a projectless contact conversation",
            "nullable": true
          },
          "project_name": {
            "type": "string",
            "description": "Project name — null for a projectless contact conversation",
            "nullable": true
          },
          "contact_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Contact ids on the client side (BSON ObjectId hex)"
          },
          "member_user_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Company-side team member ids with access to this conversation (BSON ObjectId hex)"
          },
          "participants": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_ConversationParticipant"
            },
            "description": "People on the client side of the conversation"
          },
          "participant_name": {
            "type": "string",
            "description": "Display name of the client side",
            "nullable": true
          },
          "participant_email": {
            "type": "string",
            "description": "Primary email of the client side",
            "nullable": true
          },
          "channels": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "email",
                "sms"
              ]
            },
            "description": "Channels present in this conversation"
          },
          "last_communication_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the newest message occurred (ISO8601)",
            "nullable": true
          },
          "last_message_direction": {
            "type": "string",
            "enum": [
              "inbound",
              "outbound"
            ],
            "description": "Direction of the newest message",
            "nullable": true
          },
          "last_channel": {
            "type": "string",
            "enum": [
              "email",
              "sms"
            ],
            "description": "Channel of the newest message alone, unlike channels (accumulated over every message the conversation has ever carried)",
            "nullable": true
          },
          "last_sent_at": {
            "type": "string",
            "format": "date-time",
            "description": "PER-VIEWER. When the calling member last sent into this conversation. Only populated on the Sent listing; null everywhere else",
            "nullable": true
          },
          "next_scheduled_for": {
            "type": "string",
            "format": "date-time",
            "description": "PER-VIEWER. When the calling member's soonest scheduled email here goes out (ISO8601). Only populated on the Scheduled listing; null everywhere else",
            "nullable": true
          },
          "next_scheduled_subject": {
            "type": "string",
            "description": "PER-VIEWER. Subject of that soonest scheduled email. Only populated on the Scheduled listing",
            "nullable": true
          },
          "scheduled_count": {
            "type": "integer",
            "format": "int32",
            "description": "PER-VIEWER. Emails the calling member has scheduled here. Only populated on the Scheduled listing",
            "nullable": true
          },
          "last_subject": {
            "type": "string",
            "description": "Subject of the newest message. PER-VIEWER: null when that message went to a narrower audience than the conversation and the caller was not on it",
            "nullable": true
          },
          "last_preview": {
            "type": "string",
            "description": "Plain-text preview of the newest message. PER-VIEWER: null under the same rule as last_subject",
            "nullable": true
          },
          "last_sender_id": {
            "type": "string",
            "description": "Sender of the newest message (BSON ObjectId hex)",
            "nullable": true
          },
          "last_sender": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_UserSummary"
              }
            ],
            "description": "The newest message's sender. Null unless requested with include=last_sender, for an unresolved_sms row, and when the sender no longer resolves",
            "nullable": true
          },
          "is_unread": {
            "type": "boolean",
            "description": "PER-VIEWER. Unread for the calling member"
          },
          "is_archived": {
            "type": "boolean",
            "description": "PER-VIEWER. Archived by the calling member"
          },
          "workspace_id": {
            "type": "string",
            "description": "Workspace id — pass to /communications?workspace_id= for the messages"
          },
          "workspace_kind": {
            "type": "string",
            "enum": [
              "project",
              "contact"
            ],
            "description": "Which kind of feed this is"
          },
          "last_message_id": {
            "type": "string",
            "description": "Communication id of the newest message (BSON ObjectId hex)",
            "nullable": true
          }
        },
        "required": [
          "type",
          "id",
          "project_id",
          "project_name",
          "contact_ids",
          "member_user_ids",
          "participants",
          "participant_name",
          "participant_email",
          "channels",
          "last_communication_at",
          "last_message_direction",
          "last_channel",
          "last_sent_at",
          "next_scheduled_for",
          "next_scheduled_subject",
          "scheduled_count",
          "last_subject",
          "last_preview",
          "last_sender_id",
          "last_sender",
          "is_unread",
          "is_archived",
          "workspace_id",
          "workspace_kind",
          "last_message_id"
        ]
      },
      "Api_V3_Entities_ConversationParticipant": {
        "type": "object",
        "properties": {
          "contact_id": {
            "type": "string",
            "description": "CompanyContact id (BSON ObjectId hex)",
            "nullable": true
          },
          "user_id": {
            "type": "string",
            "description": "ClientUser id (BSON ObjectId hex)",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Display name",
            "nullable": true
          },
          "email": {
            "type": "string",
            "description": "Email address",
            "nullable": true
          }
        },
        "required": [
          "contact_id",
          "user_id",
          "name",
          "email"
        ]
      },
      "Api_V3_Entities_Conversation_UnresolvedSms": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "feed",
              "unresolved_sms"
            ],
            "description": "The kind of conversation, the discriminator. One of: feed, unresolved_sms"
          },
          "id": {
            "type": "string",
            "description": "Conversation id — a BSON ObjectId hex string, UNLESS type is unresolved_sms, in which case it is an opaque synthetic sentinel"
          },
          "project_id": {
            "type": "string",
            "description": "Project (Event) id — null for a projectless contact conversation",
            "nullable": true
          },
          "project_name": {
            "type": "string",
            "description": "Project name — null for a projectless contact conversation",
            "nullable": true
          },
          "contact_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Contact ids on the client side (BSON ObjectId hex)"
          },
          "member_user_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Company-side team member ids with access to this conversation (BSON ObjectId hex)"
          },
          "participants": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_ConversationParticipant"
            },
            "description": "People on the client side of the conversation"
          },
          "participant_name": {
            "type": "string",
            "description": "Display name of the client side",
            "nullable": true
          },
          "participant_email": {
            "type": "string",
            "description": "Primary email of the client side",
            "nullable": true
          },
          "channels": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "email",
                "sms"
              ]
            },
            "description": "Channels present in this conversation"
          },
          "last_communication_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the newest message occurred (ISO8601)",
            "nullable": true
          },
          "last_message_direction": {
            "type": "string",
            "enum": [
              "inbound",
              "outbound"
            ],
            "description": "Direction of the newest message",
            "nullable": true
          },
          "last_channel": {
            "type": "string",
            "enum": [
              "email",
              "sms"
            ],
            "description": "Channel of the newest message alone, unlike channels (accumulated over every message the conversation has ever carried)",
            "nullable": true
          },
          "last_sent_at": {
            "type": "string",
            "format": "date-time",
            "description": "PER-VIEWER. When the calling member last sent into this conversation. Only populated on the Sent listing; null everywhere else",
            "nullable": true
          },
          "next_scheduled_for": {
            "type": "string",
            "format": "date-time",
            "description": "PER-VIEWER. When the calling member's soonest scheduled email here goes out (ISO8601). Only populated on the Scheduled listing; null everywhere else",
            "nullable": true
          },
          "next_scheduled_subject": {
            "type": "string",
            "description": "PER-VIEWER. Subject of that soonest scheduled email. Only populated on the Scheduled listing",
            "nullable": true
          },
          "scheduled_count": {
            "type": "integer",
            "format": "int32",
            "description": "PER-VIEWER. Emails the calling member has scheduled here. Only populated on the Scheduled listing",
            "nullable": true
          },
          "last_subject": {
            "type": "string",
            "description": "Subject of the newest message. PER-VIEWER: null when that message went to a narrower audience than the conversation and the caller was not on it",
            "nullable": true
          },
          "last_preview": {
            "type": "string",
            "description": "Plain-text preview of the newest message. PER-VIEWER: null under the same rule as last_subject",
            "nullable": true
          },
          "last_sender_id": {
            "type": "string",
            "description": "Sender of the newest message (BSON ObjectId hex)",
            "nullable": true
          },
          "last_sender": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_UserSummary"
              }
            ],
            "description": "The newest message's sender. Null unless requested with include=last_sender, for an unresolved_sms row, and when the sender no longer resolves",
            "nullable": true
          },
          "is_unread": {
            "type": "boolean",
            "description": "PER-VIEWER. Unread for the calling member"
          },
          "is_archived": {
            "type": "boolean",
            "description": "PER-VIEWER. Archived by the calling member"
          },
          "direct_message_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The DirectMessage ids to pass to POST /api/v2/direct_messages/:id/resolve, oldest first. The conversation id is a synthetic sentinel, not a usable DirectMessage id"
          },
          "participant_phone": {
            "type": "string",
            "description": "E.164 phone number of the sender"
          }
        },
        "required": [
          "type",
          "id",
          "project_id",
          "project_name",
          "contact_ids",
          "member_user_ids",
          "participants",
          "participant_name",
          "participant_email",
          "channels",
          "last_communication_at",
          "last_message_direction",
          "last_channel",
          "last_sent_at",
          "next_scheduled_for",
          "next_scheduled_subject",
          "scheduled_count",
          "last_subject",
          "last_preview",
          "last_sender_id",
          "last_sender",
          "is_unread",
          "is_archived",
          "direct_message_ids",
          "participant_phone"
        ]
      },
      "Api_V3_Entities_WorkflowStepAction_Email": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Step action id (BSON ObjectId hex)"
          },
          "type": {
            "type": "string",
            "enum": [
              "task",
              "file",
              "email",
              "flow",
              "pipeline"
            ],
            "description": "What the step does when it fires — the discriminator. One of: task, file, email, flow, pipeline"
          },
          "description": {
            "type": "string",
            "description": "Human-readable summary of the action, resolved server-side (the email template title, the task title, the file or smart file template title, the pipeline stage name)",
            "nullable": true
          },
          "completed": {
            "type": "boolean",
            "description": "Whether the action has already run"
          },
          "completed_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the action ran (ISO8601)",
            "nullable": true
          },
          "declined_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the member declined the step instead of approving it (ISO8601)",
            "nullable": true
          },
          "email_template_id": {
            "type": "string",
            "description": "Company email template the step sends (BSON ObjectId hex)",
            "nullable": true
          }
        },
        "required": [
          "id",
          "type",
          "description",
          "completed",
          "completed_at",
          "declined_at",
          "email_template_id"
        ]
      },
      "Api_V3_Entities_WorkflowStepAction_File": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Step action id (BSON ObjectId hex)"
          },
          "type": {
            "type": "string",
            "enum": [
              "task",
              "file",
              "email",
              "flow",
              "pipeline"
            ],
            "description": "What the step does when it fires — the discriminator. One of: task, file, email, flow, pipeline"
          },
          "description": {
            "type": "string",
            "description": "Human-readable summary of the action, resolved server-side (the email template title, the task title, the file or smart file template title, the pipeline stage name)",
            "nullable": true
          },
          "completed": {
            "type": "boolean",
            "description": "Whether the action has already run"
          },
          "completed_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the action ran (ISO8601)",
            "nullable": true
          },
          "declined_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the member declined the step instead of approving it (ISO8601)",
            "nullable": true
          },
          "file_template_id": {
            "type": "string",
            "description": "Legacy file template the step sends (BSON ObjectId hex)",
            "nullable": true
          },
          "email_template_id": {
            "type": "string",
            "description": "Company email template the file is sent with (BSON ObjectId hex)",
            "nullable": true
          },
          "file_type": {
            "type": "string",
            "enum": [
              "proposal",
              "invoice",
              "direct_payment",
              "questionnaire",
              "brochure",
              "timeline",
              "agreement"
            ],
            "description": "Kind of legacy file the step sends. One of: proposal, invoice, direct_payment, questionnaire, brochure, timeline, agreement",
            "nullable": true
          }
        },
        "required": [
          "id",
          "type",
          "description",
          "completed",
          "completed_at",
          "declined_at",
          "file_template_id",
          "email_template_id",
          "file_type"
        ]
      },
      "Api_V3_Entities_WorkflowStepAction_Flow": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Step action id (BSON ObjectId hex)"
          },
          "type": {
            "type": "string",
            "enum": [
              "task",
              "file",
              "email",
              "flow",
              "pipeline"
            ],
            "description": "What the step does when it fires — the discriminator. One of: task, file, email, flow, pipeline"
          },
          "description": {
            "type": "string",
            "description": "Human-readable summary of the action, resolved server-side (the email template title, the task title, the file or smart file template title, the pipeline stage name)",
            "nullable": true
          },
          "completed": {
            "type": "boolean",
            "description": "Whether the action has already run"
          },
          "completed_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the action ran (ISO8601)",
            "nullable": true
          },
          "declined_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the member declined the step instead of approving it (ISO8601)",
            "nullable": true
          },
          "file_template_id": {
            "type": "string",
            "description": "Smart file template the step sends (BSON ObjectId hex)",
            "nullable": true
          },
          "email_template_id": {
            "type": "string",
            "description": "Company email template the smart file is sent with (BSON ObjectId hex)",
            "nullable": true
          }
        },
        "required": [
          "id",
          "type",
          "description",
          "completed",
          "completed_at",
          "declined_at",
          "file_template_id",
          "email_template_id"
        ]
      },
      "Api_V3_Entities_WorkflowStepAction_Pipeline": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Step action id (BSON ObjectId hex)"
          },
          "type": {
            "type": "string",
            "enum": [
              "task",
              "file",
              "email",
              "flow",
              "pipeline"
            ],
            "description": "What the step does when it fires — the discriminator. One of: task, file, email, flow, pipeline"
          },
          "description": {
            "type": "string",
            "description": "Human-readable summary of the action, resolved server-side (the email template title, the task title, the file or smart file template title, the pipeline stage name)",
            "nullable": true
          },
          "completed": {
            "type": "boolean",
            "description": "Whether the action has already run"
          },
          "completed_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the action ran (ISO8601)",
            "nullable": true
          },
          "declined_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the member declined the step instead of approving it (ISO8601)",
            "nullable": true
          },
          "pipeline_stage_id": {
            "type": "string",
            "description": "Pipeline stage the step moves the project to (BSON ObjectId hex)",
            "nullable": true
          },
          "pipeline_stage_name": {
            "type": "string",
            "description": "Stage name as it was when the step was defined",
            "nullable": true
          }
        },
        "required": [
          "id",
          "type",
          "description",
          "completed",
          "completed_at",
          "declined_at",
          "pipeline_stage_id",
          "pipeline_stage_name"
        ]
      },
      "Api_V3_Entities_WorkflowStepAction_Task": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Step action id (BSON ObjectId hex)"
          },
          "type": {
            "type": "string",
            "enum": [
              "task",
              "file",
              "email",
              "flow",
              "pipeline"
            ],
            "description": "What the step does when it fires — the discriminator. One of: task, file, email, flow, pipeline"
          },
          "description": {
            "type": "string",
            "description": "Human-readable summary of the action, resolved server-side (the email template title, the task title, the file or smart file template title, the pipeline stage name)",
            "nullable": true
          },
          "completed": {
            "type": "boolean",
            "description": "Whether the action has already run"
          },
          "completed_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the action ran (ISO8601)",
            "nullable": true
          },
          "declined_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the member declined the step instead of approving it (ISO8601)",
            "nullable": true
          },
          "task_title": {
            "type": "string",
            "description": "Title of the task the step creates",
            "nullable": true
          }
        },
        "required": [
          "id",
          "type",
          "description",
          "completed",
          "completed_at",
          "declined_at",
          "task_title"
        ]
      },
      "Api_V3_Entities_WorkspaceAttachment_Bookmark": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "objectid",
            "description": "Attachment id"
          },
          "type": {
            "type": "string",
            "enum": [
              "image",
              "file",
              "bookmark"
            ],
            "description": "What was attached — the discriminator. One of: image, file, bookmark"
          },
          "name": {
            "type": "string",
            "description": "Display name: the file name, or the bookmark title",
            "nullable": true
          },
          "url": {
            "type": "string",
            "description": "Where the attachment opens or downloads from",
            "nullable": true
          },
          "file_type": {
            "type": "string",
            "description": "File extension, lowercase (for example pdf); null for a bookmark",
            "nullable": true
          },
          "size": {
            "type": "integer",
            "format": "int32",
            "description": "Size in bytes; null for a bookmark",
            "nullable": true
          },
          "thumbnail": {
            "type": "string",
            "description": "Preview image URL; null when the attachment has no preview",
            "nullable": true
          },
          "workspace_id": {
            "type": "string",
            "format": "objectid",
            "description": "Workspace the attachment belongs to"
          },
          "creator_id": {
            "type": "string",
            "format": "objectid",
            "description": "User who attached it",
            "nullable": true
          },
          "flow_id": {
            "type": "string",
            "format": "objectid",
            "description": "Smart file the attachment was collected for, if any",
            "nullable": true
          },
          "deletable": {
            "type": "boolean",
            "description": "PER-VIEWER. Whether the CALLER may delete this attachment"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Creation time (ISO8601)"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601)"
          },
          "favicon": {
            "type": "string",
            "description": "Favicon URL of the bookmarked site",
            "nullable": true
          },
          "default_permission": {
            "type": "string",
            "enum": [
              "no_permissions",
              "view_only",
              "full_access"
            ],
            "description": "What every workspace member may do with the bookmark unless a per-user permission says otherwise"
          },
          "permissions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_WorkspaceAttachmentPermission"
            },
            "description": "Per-user permissions that override the default"
          }
        },
        "required": [
          "id",
          "type",
          "name",
          "url",
          "file_type",
          "size",
          "thumbnail",
          "workspace_id",
          "creator_id",
          "flow_id",
          "deletable",
          "created_at",
          "updated_at",
          "favicon",
          "default_permission",
          "permissions"
        ]
      },
      "Api_V3_Entities_WorkspaceAttachmentPermission": {
        "type": "object",
        "properties": {
          "user_id": {
            "type": "string",
            "format": "objectid",
            "description": "User the permission applies to"
          },
          "permission": {
            "type": "string",
            "enum": [
              "no_permissions",
              "view_only",
              "full_access"
            ],
            "description": "What the user may do with the bookmark"
          }
        },
        "required": [
          "user_id",
          "permission"
        ]
      },
      "Api_V3_Entities_WorkspaceAttachment_File": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "objectid",
            "description": "Attachment id"
          },
          "type": {
            "type": "string",
            "enum": [
              "image",
              "file",
              "bookmark"
            ],
            "description": "What was attached — the discriminator. One of: image, file, bookmark"
          },
          "name": {
            "type": "string",
            "description": "Display name: the file name, or the bookmark title",
            "nullable": true
          },
          "url": {
            "type": "string",
            "description": "Where the attachment opens or downloads from",
            "nullable": true
          },
          "file_type": {
            "type": "string",
            "description": "File extension, lowercase (for example pdf); null for a bookmark",
            "nullable": true
          },
          "size": {
            "type": "integer",
            "format": "int32",
            "description": "Size in bytes; null for a bookmark",
            "nullable": true
          },
          "thumbnail": {
            "type": "string",
            "description": "Preview image URL; null when the attachment has no preview",
            "nullable": true
          },
          "workspace_id": {
            "type": "string",
            "format": "objectid",
            "description": "Workspace the attachment belongs to"
          },
          "creator_id": {
            "type": "string",
            "format": "objectid",
            "description": "User who attached it",
            "nullable": true
          },
          "flow_id": {
            "type": "string",
            "format": "objectid",
            "description": "Smart file the attachment was collected for, if any",
            "nullable": true
          },
          "deletable": {
            "type": "boolean",
            "description": "PER-VIEWER. Whether the CALLER may delete this attachment"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Creation time (ISO8601)"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601)"
          }
        },
        "required": [
          "id",
          "type",
          "name",
          "url",
          "file_type",
          "size",
          "thumbnail",
          "workspace_id",
          "creator_id",
          "flow_id",
          "deletable",
          "created_at",
          "updated_at"
        ]
      },
      "Api_V3_Entities_WorkspaceAttachment_Image": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "objectid",
            "description": "Attachment id"
          },
          "type": {
            "type": "string",
            "enum": [
              "image",
              "file",
              "bookmark"
            ],
            "description": "What was attached — the discriminator. One of: image, file, bookmark"
          },
          "name": {
            "type": "string",
            "description": "Display name: the file name, or the bookmark title",
            "nullable": true
          },
          "url": {
            "type": "string",
            "description": "Where the attachment opens or downloads from",
            "nullable": true
          },
          "file_type": {
            "type": "string",
            "description": "File extension, lowercase (for example pdf); null for a bookmark",
            "nullable": true
          },
          "size": {
            "type": "integer",
            "format": "int32",
            "description": "Size in bytes; null for a bookmark",
            "nullable": true
          },
          "thumbnail": {
            "type": "string",
            "description": "Preview image URL; null when the attachment has no preview",
            "nullable": true
          },
          "workspace_id": {
            "type": "string",
            "format": "objectid",
            "description": "Workspace the attachment belongs to"
          },
          "creator_id": {
            "type": "string",
            "format": "objectid",
            "description": "User who attached it",
            "nullable": true
          },
          "flow_id": {
            "type": "string",
            "format": "objectid",
            "description": "Smart file the attachment was collected for, if any",
            "nullable": true
          },
          "deletable": {
            "type": "boolean",
            "description": "PER-VIEWER. Whether the CALLER may delete this attachment"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Creation time (ISO8601)"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601)"
          },
          "cloudinary_public_id": {
            "type": "string",
            "description": "Cloudinary public id, so a client may derive its own transformations",
            "nullable": true
          },
          "width": {
            "type": "integer",
            "format": "int32",
            "description": "Source width in pixels",
            "nullable": true
          },
          "height": {
            "type": "integer",
            "format": "int32",
            "description": "Source height in pixels",
            "nullable": true
          }
        },
        "required": [
          "id",
          "type",
          "name",
          "url",
          "file_type",
          "size",
          "thumbnail",
          "workspace_id",
          "creator_id",
          "flow_id",
          "deletable",
          "created_at",
          "updated_at",
          "cloudinary_public_id",
          "width",
          "height"
        ]
      },
      "Api_V3_Entities_FeatureConfig_AiDiscoverability": {
        "type": "object",
        "properties": {
          "feature_name": {
            "type": "string",
            "description": "Feature config key (e.g. scheduler, calendar, finance)"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the feature is enabled"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601); null if never saved",
            "nullable": true
          },
          "eligible": {
            "type": "boolean",
            "description": "PER-VIEWER. Whether the caller may use the feature; null when the feature has no eligibility rule (the resource MUST still pass an entry per config)",
            "nullable": true
          },
          "lead_form_id": {
            "type": "string",
            "description": "Flow id of the lead form; null when unset or the feature is disabled",
            "nullable": true
          }
        },
        "required": [
          "feature_name",
          "enabled",
          "updated_at",
          "eligible",
          "lead_form_id"
        ]
      },
      "Api_V3_Entities_FeatureConfig_AiSuggestion": {
        "type": "object",
        "properties": {
          "feature_name": {
            "type": "string",
            "description": "Feature config key (e.g. scheduler, calendar, finance)"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the feature is enabled"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601); null if never saved",
            "nullable": true
          },
          "eligible": {
            "type": "boolean",
            "description": "PER-VIEWER. Whether the caller may use the feature; null when the feature has no eligibility rule (the resource MUST still pass an entry per config)",
            "nullable": true
          },
          "opt_in_composer_ai_injection": {
            "type": "boolean",
            "description": "Whether the AI composer may inject suggestions"
          },
          "opt_in_leads_follow_up": {
            "type": "boolean",
            "description": "Whether leads follow-up suggestions are on"
          },
          "leads_follow_up_timeframe": {
            "type": "string",
            "enum": [
              "HOUR",
              "DAY",
              "MONTH",
              "YEAR"
            ],
            "description": "Unit of the follow-up timeframe"
          },
          "leads_follow_up_timeframe_value": {
            "type": "integer",
            "format": "int32",
            "description": "Number of timeframe units to wait before a follow-up"
          }
        },
        "required": [
          "feature_name",
          "enabled",
          "updated_at",
          "eligible",
          "opt_in_composer_ai_injection",
          "opt_in_leads_follow_up",
          "leads_follow_up_timeframe",
          "leads_follow_up_timeframe_value"
        ]
      },
      "Api_V3_Entities_FeatureConfig_AttributionCapture": {
        "type": "object",
        "properties": {
          "feature_name": {
            "type": "string",
            "description": "Feature config key (e.g. scheduler, calendar, finance)"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the feature is enabled"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601); null if never saved",
            "nullable": true
          },
          "eligible": {
            "type": "boolean",
            "description": "PER-VIEWER. Whether the caller may use the feature; null when the feature has no eligibility rule (the resource MUST still pass an entry per config)",
            "nullable": true
          }
        },
        "required": [
          "feature_name",
          "enabled",
          "updated_at",
          "eligible"
        ]
      },
      "Api_V3_Entities_FeatureConfig_BusinessTrends": {
        "type": "object",
        "properties": {
          "feature_name": {
            "type": "string",
            "description": "Feature config key (e.g. scheduler, calendar, finance)"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the feature is enabled"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601); null if never saved",
            "nullable": true
          },
          "eligible": {
            "type": "boolean",
            "description": "PER-VIEWER. Whether the caller may use the feature; null when the feature has no eligibility rule (the resource MUST still pass an entry per config)",
            "nullable": true
          }
        },
        "required": [
          "feature_name",
          "enabled",
          "updated_at",
          "eligible"
        ]
      },
      "Api_V3_Entities_FeatureConfig_Calendar": {
        "type": "object",
        "properties": {
          "feature_name": {
            "type": "string",
            "description": "Feature config key (e.g. scheduler, calendar, finance)"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the feature is enabled"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601); null if never saved",
            "nullable": true
          },
          "eligible": {
            "type": "boolean",
            "description": "PER-VIEWER. Whether the caller may use the feature; null when the feature has no eligibility rule (the resource MUST still pass an entry per config)",
            "nullable": true
          }
        },
        "required": [
          "feature_name",
          "enabled",
          "updated_at",
          "eligible"
        ]
      },
      "Api_V3_Entities_FeatureConfig_Expenses": {
        "type": "object",
        "properties": {
          "feature_name": {
            "type": "string",
            "description": "Feature config key (e.g. scheduler, calendar, finance)"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the feature is enabled"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601); null if never saved",
            "nullable": true
          },
          "eligible": {
            "type": "boolean",
            "description": "PER-VIEWER. Whether the caller may use the feature; null when the feature has no eligibility rule (the resource MUST still pass an entry per config)",
            "nullable": true
          }
        },
        "required": [
          "feature_name",
          "enabled",
          "updated_at",
          "eligible"
        ]
      },
      "Api_V3_Entities_FeatureConfig_Finance": {
        "type": "object",
        "properties": {
          "feature_name": {
            "type": "string",
            "description": "Feature config key (e.g. scheduler, calendar, finance)"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the feature is enabled"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601); null if never saved",
            "nullable": true
          },
          "eligible": {
            "type": "boolean",
            "description": "PER-VIEWER. Whether the caller may use the feature; null when the feature has no eligibility rule (the resource MUST still pass an entry per config)",
            "nullable": true
          }
        },
        "required": [
          "feature_name",
          "enabled",
          "updated_at",
          "eligible"
        ]
      },
      "Api_V3_Entities_FeatureConfig_FinanceOverview": {
        "type": "object",
        "properties": {
          "feature_name": {
            "type": "string",
            "description": "Feature config key (e.g. scheduler, calendar, finance)"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the feature is enabled"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601); null if never saved",
            "nullable": true
          },
          "eligible": {
            "type": "boolean",
            "description": "PER-VIEWER. Whether the caller may use the feature; null when the feature has no eligibility rule (the resource MUST still pass an entry per config)",
            "nullable": true
          }
        },
        "required": [
          "feature_name",
          "enabled",
          "updated_at",
          "eligible"
        ]
      },
      "Api_V3_Entities_FeatureConfig_HotLeads": {
        "type": "object",
        "properties": {
          "feature_name": {
            "type": "string",
            "description": "Feature config key (e.g. scheduler, calendar, finance)"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the feature is enabled"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601); null if never saved",
            "nullable": true
          },
          "eligible": {
            "type": "boolean",
            "description": "PER-VIEWER. Whether the caller may use the feature; null when the feature has no eligibility rule (the resource MUST still pass an entry per config)",
            "nullable": true
          }
        },
        "required": [
          "feature_name",
          "enabled",
          "updated_at",
          "eligible"
        ]
      },
      "Api_V3_Entities_FeatureConfig_PayLink": {
        "type": "object",
        "properties": {
          "feature_name": {
            "type": "string",
            "description": "Feature config key (e.g. scheduler, calendar, finance)"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the feature is enabled"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601); null if never saved",
            "nullable": true
          },
          "eligible": {
            "type": "boolean",
            "description": "PER-VIEWER. Whether the caller may use the feature; null when the feature has no eligibility rule (the resource MUST still pass an entry per config)",
            "nullable": true
          }
        },
        "required": [
          "feature_name",
          "enabled",
          "updated_at",
          "eligible"
        ]
      },
      "Api_V3_Entities_FeatureConfig_Pictime": {
        "type": "object",
        "properties": {
          "feature_name": {
            "type": "string",
            "description": "Feature config key (e.g. scheduler, calendar, finance)"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the feature is enabled"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601); null if never saved",
            "nullable": true
          },
          "eligible": {
            "type": "boolean",
            "description": "PER-VIEWER. Whether the caller may use the feature; null when the feature has no eligibility rule (the resource MUST still pass an entry per config)",
            "nullable": true
          }
        },
        "required": [
          "feature_name",
          "enabled",
          "updated_at",
          "eligible"
        ]
      },
      "Api_V3_Entities_FeatureConfig_PriorityList": {
        "type": "object",
        "properties": {
          "feature_name": {
            "type": "string",
            "description": "Feature config key (e.g. scheduler, calendar, finance)"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the feature is enabled"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601); null if never saved",
            "nullable": true
          },
          "eligible": {
            "type": "boolean",
            "description": "PER-VIEWER. Whether the caller may use the feature; null when the feature has no eligibility rule (the resource MUST still pass an entry per config)",
            "nullable": true
          }
        },
        "required": [
          "feature_name",
          "enabled",
          "updated_at",
          "eligible"
        ]
      },
      "Api_V3_Entities_FeatureConfig_Prismm": {
        "type": "object",
        "properties": {
          "feature_name": {
            "type": "string",
            "description": "Feature config key (e.g. scheduler, calendar, finance)"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the feature is enabled"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601); null if never saved",
            "nullable": true
          },
          "eligible": {
            "type": "boolean",
            "description": "PER-VIEWER. Whether the caller may use the feature; null when the feature has no eligibility rule (the resource MUST still pass an entry per config)",
            "nullable": true
          }
        },
        "required": [
          "feature_name",
          "enabled",
          "updated_at",
          "eligible"
        ]
      },
      "Api_V3_Entities_FeatureConfig_Quickbooks": {
        "type": "object",
        "properties": {
          "feature_name": {
            "type": "string",
            "description": "Feature config key (e.g. scheduler, calendar, finance)"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the feature is enabled"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601); null if never saved",
            "nullable": true
          },
          "eligible": {
            "type": "boolean",
            "description": "PER-VIEWER. Whether the caller may use the feature; null when the feature has no eligibility rule (the resource MUST still pass an entry per config)",
            "nullable": true
          }
        },
        "required": [
          "feature_name",
          "enabled",
          "updated_at",
          "eligible"
        ]
      },
      "Api_V3_Entities_FeatureConfig_ReferralRequestSuggestion": {
        "type": "object",
        "properties": {
          "feature_name": {
            "type": "string",
            "description": "Feature config key (e.g. scheduler, calendar, finance)"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the feature is enabled"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601); null if never saved",
            "nullable": true
          },
          "eligible": {
            "type": "boolean",
            "description": "PER-VIEWER. Whether the caller may use the feature; null when the feature has no eligibility rule (the resource MUST still pass an entry per config)",
            "nullable": true
          }
        },
        "required": [
          "feature_name",
          "enabled",
          "updated_at",
          "eligible"
        ]
      },
      "Api_V3_Entities_FeatureConfig_Reports": {
        "type": "object",
        "properties": {
          "feature_name": {
            "type": "string",
            "description": "Feature config key (e.g. scheduler, calendar, finance)"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the feature is enabled"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601); null if never saved",
            "nullable": true
          },
          "eligible": {
            "type": "boolean",
            "description": "PER-VIEWER. Whether the caller may use the feature; null when the feature has no eligibility rule (the resource MUST still pass an entry per config)",
            "nullable": true
          }
        },
        "required": [
          "feature_name",
          "enabled",
          "updated_at",
          "eligible"
        ]
      },
      "Api_V3_Entities_FeatureConfig_Scheduler": {
        "type": "object",
        "properties": {
          "feature_name": {
            "type": "string",
            "description": "Feature config key (e.g. scheduler, calendar, finance)"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the feature is enabled"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601); null if never saved",
            "nullable": true
          },
          "eligible": {
            "type": "boolean",
            "description": "PER-VIEWER. Whether the caller may use the feature; null when the feature has no eligibility rule (the resource MUST still pass an entry per config)",
            "nullable": true
          }
        },
        "required": [
          "feature_name",
          "enabled",
          "updated_at",
          "eligible"
        ]
      },
      "Api_V3_Entities_FeatureConfig_SuggestedArchivedWorkspace": {
        "type": "object",
        "properties": {
          "feature_name": {
            "type": "string",
            "description": "Feature config key (e.g. scheduler, calendar, finance)"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the feature is enabled"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601); null if never saved",
            "nullable": true
          },
          "eligible": {
            "type": "boolean",
            "description": "PER-VIEWER. Whether the caller may use the feature; null when the feature has no eligibility rule (the resource MUST still pass an entry per config)",
            "nullable": true
          }
        },
        "required": [
          "feature_name",
          "enabled",
          "updated_at",
          "eligible"
        ]
      },
      "Api_V3_Entities_FeatureConfig_Tasks": {
        "type": "object",
        "properties": {
          "feature_name": {
            "type": "string",
            "description": "Feature config key (e.g. scheduler, calendar, finance)"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the feature is enabled"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601); null if never saved",
            "nullable": true
          },
          "eligible": {
            "type": "boolean",
            "description": "PER-VIEWER. Whether the caller may use the feature; null when the feature has no eligibility rule (the resource MUST still pass an entry per config)",
            "nullable": true
          }
        },
        "required": [
          "feature_name",
          "enabled",
          "updated_at",
          "eligible"
        ]
      },
      "Api_V3_Entities_FeatureConfig_Taxes": {
        "type": "object",
        "properties": {
          "feature_name": {
            "type": "string",
            "description": "Feature config key (e.g. scheduler, calendar, finance)"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the feature is enabled"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601); null if never saved",
            "nullable": true
          },
          "eligible": {
            "type": "boolean",
            "description": "PER-VIEWER. Whether the caller may use the feature; null when the feature has no eligibility rule (the resource MUST still pass an entry per config)",
            "nullable": true
          }
        },
        "required": [
          "feature_name",
          "enabled",
          "updated_at",
          "eligible"
        ]
      },
      "Api_V3_Entities_FeatureConfig_TimeTracker": {
        "type": "object",
        "properties": {
          "feature_name": {
            "type": "string",
            "description": "Feature config key (e.g. scheduler, calendar, finance)"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the feature is enabled"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601); null if never saved",
            "nullable": true
          },
          "eligible": {
            "type": "boolean",
            "description": "PER-VIEWER. Whether the caller may use the feature; null when the feature has no eligibility rule (the resource MUST still pass an entry per config)",
            "nullable": true
          }
        },
        "required": [
          "feature_name",
          "enabled",
          "updated_at",
          "eligible"
        ]
      },
      "Api_V3_Entities_FeatureConfig_UnconvertedLeadFollowupSuggestions": {
        "type": "object",
        "properties": {
          "feature_name": {
            "type": "string",
            "description": "Feature config key (e.g. scheduler, calendar, finance)"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the feature is enabled"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601); null if never saved",
            "nullable": true
          },
          "eligible": {
            "type": "boolean",
            "description": "PER-VIEWER. Whether the caller may use the feature; null when the feature has no eligibility rule (the resource MUST still pass an entry per config)",
            "nullable": true
          }
        },
        "required": [
          "feature_name",
          "enabled",
          "updated_at",
          "eligible"
        ]
      },
      "Api_V3_Entities_FeatureConfig_UnresponsiveLeadFollowupSuggestions": {
        "type": "object",
        "properties": {
          "feature_name": {
            "type": "string",
            "description": "Feature config key (e.g. scheduler, calendar, finance)"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the feature is enabled"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601); null if never saved",
            "nullable": true
          },
          "eligible": {
            "type": "boolean",
            "description": "PER-VIEWER. Whether the caller may use the feature; null when the feature has no eligibility rule (the resource MUST still pass an entry per config)",
            "nullable": true
          }
        },
        "required": [
          "feature_name",
          "enabled",
          "updated_at",
          "eligible"
        ]
      },
      "Api_V3_Entities_FeatureConfig_VenueAutomationTemplates": {
        "type": "object",
        "properties": {
          "feature_name": {
            "type": "string",
            "description": "Feature config key (e.g. scheduler, calendar, finance)"
          },
          "enabled": {
            "type": "boolean",
            "description": "Whether the feature is enabled"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601); null if never saved",
            "nullable": true
          },
          "eligible": {
            "type": "boolean",
            "description": "PER-VIEWER. Whether the caller may use the feature; null when the feature has no eligibility rule (the resource MUST still pass an entry per config)",
            "nullable": true
          }
        },
        "required": [
          "feature_name",
          "enabled",
          "updated_at",
          "eligible"
        ]
      },
      "createContact": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "description": "Contact email (the natural key within a company)"
          },
          "kind": {
            "type": "string",
            "description": "Party kind: client (default) or vendor",
            "enum": [
              "client",
              "vendor"
            ],
            "default": "client"
          },
          "full_name": {
            "type": "string",
            "description": "Display name; split into first/last server-side"
          },
          "phone_number": {
            "type": "string"
          },
          "address": {
            "type": "string",
            "description": "Mailing address (flat string)"
          },
          "job_title": {
            "type": "string"
          },
          "website_url": {
            "type": "string"
          },
          "company_name": {
            "type": "string",
            "description": "Contact's company name"
          },
          "company_type": {
            "type": "string",
            "description": "Contact's business kind (snake_case enum)"
          },
          "private_notes": {
            "type": "string",
            "description": "Private note (per-viewer; stored against the caller)"
          },
          "source": {
            "type": "string",
            "description": "How this contact was added: manual (default) or vendor_referral (created through the refer-a-vendor flow, which attributes the referral)",
            "enum": [
              "manual",
              "vendor_referral"
            ],
            "default": "manual"
          },
          "client_organization": {
            "type": "object",
            "description": "Attach the new client to the company's client organization with this name, creating the organization if it does not exist yet (case-insensitive match within the company). The fields other than name are written only when the organization is created; an existing one is left as it is. Ignored for a vendor contact.",
            "properties": {
              "name": {
                "type": "string",
                "description": "Organization name — the natural key within the company"
              },
              "phone_number": {
                "type": "string"
              },
              "website_url": {
                "type": "string"
              },
              "address": {
                "type": "string",
                "description": "Mailing address (flat string)"
              },
              "company_type": {
                "type": "string",
                "description": "The organization's business kind (snake_case enum)"
              },
              "private_notes": {
                "type": "string",
                "description": "Private note on the organization"
              }
            },
            "required": [
              "name"
            ]
          },
          "sms_consent_confirmed": {
            "type": "boolean",
            "description": "The member confirms this client consented to SMS. true records the consent (requires phone_number); false revokes any existing consent. Omit to leave consent untouched. Client contacts only."
          },
          "custom_fields": {
            "type": "array",
            "description": "Values for the company's custom fields of this record's kind. MERGE, not replace: only the listed fields are written, the rest keep their value. Each entry is validated like `PATCH .../custom_fields/:field_id` before anything is written: an unknown, foreign, archived or wrong-kind `field_id` is a 404; an invalid `value`, a repeated `field_id` or more than 50 entries is a 400, and nothing is written.",
            "items": {
              "type": "object",
              "properties": {
                "field_id": {
                  "type": "string",
                  "description": "Custom field id (the `id` of a GET /custom_fields row)"
                },
                "value": {
                  "type": "string",
                  "description": "The new value as a String: a number as its digits, a date as ISO8601, a single_select as the option's id, a multi_select as comma-separated option ids. `null` clears the value."
                }
              },
              "required": [
                "field_id",
                "value"
              ]
            }
          },
          "interaction": {
            "type": "object",
            "description": "Log an initial last-interaction on the new contact",
            "properties": {
              "type": {
                "type": "string",
                "description": "How the interaction happened (manual, email, meeting, lead_form, contact_form)",
                "enum": [
                  "manual",
                  "email",
                  "meeting",
                  "lead_form",
                  "contact_form"
                ]
              },
              "context_type": {
                "type": "string",
                "description": "Where the interaction happened (Event, CompanyContact, ClientOrganization)",
                "enum": [
                  "Event",
                  "CompanyContact",
                  "ClientOrganization"
                ]
              },
              "interaction_at": {
                "type": "string",
                "format": "date-time",
                "description": "When the interaction happened (ISO8601)"
              }
            }
          },
          "include": {
            "type": "array",
            "description": "Comma-separated relations to populate. Allowed: user, action_suggestions, workspaces, tags, client_organization, custom_fields, enrichment. A relation not requested is null. Nested paths (a.b) are not supported.",
            "items": {
              "type": "string",
              "enum": [
                "user",
                "action_suggestions",
                "workspaces",
                "tags",
                "client_organization",
                "custom_fields",
                "enrichment"
              ]
            }
          },
          "max_action_suggestions": {
            "type": "integer",
            "format": "int32",
            "description": "Max action_suggestions per row (1..25, default 3). Ordered by expires_at asc. Requires include=action_suggestions.",
            "minimum": 1,
            "maximum": 25
          },
          "max_workspaces": {
            "type": "integer",
            "format": "int32",
            "description": "Max workspaces per row (1..25, default 3). Ordered by _id desc. Requires include=workspaces.",
            "minimum": 1,
            "maximum": 25
          },
          "max_tags": {
            "type": "integer",
            "format": "int32",
            "description": "Max tags per row (1..25, default 25). Ordered by name asc. Requires include=tags.",
            "minimum": 1,
            "maximum": 25
          },
          "max_custom_fields": {
            "type": "integer",
            "format": "int32",
            "description": "Max custom_fields per row (1..50, default 50). Ordered by order asc. Requires include=custom_fields.",
            "minimum": 1,
            "maximum": 50
          }
        },
        "required": [
          "email"
        ],
        "description": "Create a contact"
      },
      "Api_V3_Entities_Contact": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Contact id (BSON ObjectId hex)"
          },
          "company_id": {
            "type": "string",
            "description": "Owning company id (BSON ObjectId hex)"
          },
          "client_id": {
            "type": "string",
            "description": "Linked client user id, if this contact is a client (BSON ObjectId hex)",
            "nullable": true
          },
          "vendor_id": {
            "type": "string",
            "description": "Linked vendor user id, if this contact is a vendor (BSON ObjectId hex)",
            "nullable": true
          },
          "user_id": {
            "type": "string",
            "description": "The linked user id (vendor_id when a vendor, else client_id) (BSON ObjectId hex)",
            "nullable": true
          },
          "client_organization_id": {
            "type": "string",
            "description": "The client organization the linked client user belongs to, if any (BSON ObjectId hex). Published only when the organization RESOLVES within the caller's company, so it is null for a contact with no linked client, for an individual (non-business) client, when the organization belongs to another company (a ClientUser can be linked to contacts in more than one company), and when it has been deleted. Unlike other bare *_id fields this is therefore not the raw stored reference.",
            "nullable": true
          },
          "user": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_UserSummary"
              }
            ],
            "description": "The linked client/vendor user, incl. avatar_url. null unless ?include=user (and null if that user is gone).",
            "nullable": true
          },
          "kind": {
            "type": "string",
            "description": "Party discriminator. One of: client, vendor",
            "nullable": true
          },
          "first_name": {
            "type": "string",
            "description": "Given name",
            "nullable": true
          },
          "last_name": {
            "type": "string",
            "description": "Family name",
            "nullable": true
          },
          "full_name": {
            "type": "string",
            "description": "Display name (first + last)",
            "nullable": true
          },
          "email": {
            "type": "string",
            "description": "Email address",
            "nullable": true
          },
          "phone_number": {
            "type": "string",
            "description": "Phone number",
            "nullable": true
          },
          "address": {
            "type": "string",
            "description": "Mailing address (flat string)",
            "nullable": true
          },
          "website_url": {
            "type": "string",
            "description": "Website URL",
            "nullable": true
          },
          "company_name": {
            "type": "string",
            "description": "Contact's company name",
            "nullable": true
          },
          "company_type": {
            "type": "string",
            "description": "Contact's business kind (lowercase snake_case enum, e.g. photographer, planner)",
            "nullable": true
          },
          "job_title": {
            "type": "string",
            "description": "Job title",
            "nullable": true
          },
          "private_notes": {
            "type": "string",
            "description": "Private note about this contact. PER-VIEWER: each vendor sees only their own note (resolved against the authenticated caller), never a teammate's.",
            "nullable": true
          },
          "preferred": {
            "type": "boolean",
            "description": "Marked as a preferred vendor"
          },
          "manually_added": {
            "type": "boolean",
            "description": "Added by hand (vs. imported/derived)"
          },
          "unsubscribed": {
            "type": "boolean",
            "description": "Unsubscribed from this company's commercial emails"
          },
          "sandboxed": {
            "type": "boolean",
            "description": "This contact is part of the company's onboarding sandbox (demo data), not a real person"
          },
          "tag_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Tag ids attached to this contact (BSON ObjectId hex)",
            "nullable": true
          },
          "interaction": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_ContactInteraction"
              }
            ],
            "description": "The last logged interaction with this contact",
            "nullable": true
          },
          "action_suggestions": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_ActionSuggestion_Projection"
              }
            ],
            "description": "Live, unexpired AI follow-up suggestions for this contact, soonest-expiring first. null unless ?include=action_suggestions; `{ data: [], total_items: 0 }` when there are none or the company has follow-up suggestions switched off.",
            "nullable": true
          },
          "workspaces": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_WorkspaceMembership_Projection"
              }
            ],
            "description": "The contact's projects as they look to the caller, newest first. null unless ?include=workspaces; `{ data: [], total_items: 0 }` when the contact is on none. These are CoupleCard projects — NOT the messaging workspace, which is its own resource (POST /contacts/:id/conversation).",
            "nullable": true
          },
          "tags": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_Tag_Projection"
              }
            ],
            "description": "The tags attached to this contact, ordered by name (case-insensitive). null unless ?include=tags; capped by max_tags, with the true total in total_items.",
            "nullable": true
          },
          "client_organization": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_ClientOrganizationSummary"
              }
            ],
            "description": "The client business this contact belongs to. null unless ?include=client_organization, null for an individual client or a contact with no linked client, and null if the organization has been deleted.",
            "nullable": true
          },
          "enrichment": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_ContactEnrichment"
              }
            ],
            "description": "Lead intelligence about the person behind this contact (their business, social presence, size and age), whether an enrichment run succeeded, and the member's reaction to it. null unless ?include=enrichment, and null for a vendor contact or one with no linked client user.",
            "nullable": true
          },
          "sms_consent_confirmed": {
            "type": "boolean",
            "description": "Whether the linked client user has a live SMS consent on file — the gate on texting this contact. False for a vendor contact, for a contact with no linked client user, and when the newest consent is revoked or predates the current consent text version. NOT company-scoped: a consent given to any company counts (parity with v2 ClientUser#valid_sms_consent?, which ignores SmsConsent#company_id)."
          },
          "user_source": {
            "type": "string",
            "description": "How the person behind this contact first entered HoneyBook (lowercase enum, e.g. manual, vendor_referral, ai_lead_suggestion) — the PERSON's provenance, not this company's copy of it, so two companies that both know them see the same value. null for a contact whose linked user is missing or soft-deleted.",
            "nullable": true
          },
          "custom_fields": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_CustomFieldValue_Projection"
              }
            ],
            "description": "The contact's custom field values, in the member's own field order — one row per LIVE field, with `value` null when unset. null unless ?include=custom_fields; `{ data: [], total_items: 0 }` when the company defines none.",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Creation time (ISO8601)"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601)"
          }
        },
        "required": [
          "id",
          "company_id",
          "client_id",
          "vendor_id",
          "user_id",
          "client_organization_id",
          "user",
          "kind",
          "first_name",
          "last_name",
          "full_name",
          "email",
          "phone_number",
          "address",
          "website_url",
          "company_name",
          "company_type",
          "job_title",
          "private_notes",
          "preferred",
          "manually_added",
          "unsubscribed",
          "sandboxed",
          "tag_ids",
          "interaction",
          "action_suggestions",
          "workspaces",
          "tags",
          "client_organization",
          "enrichment",
          "sms_consent_confirmed",
          "user_source",
          "custom_fields",
          "created_at",
          "updated_at"
        ],
        "description": "Api_V3_Entities_Contact model"
      },
      "Api_V3_Entities_ContactInteraction": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "How the interaction happened. One of: manual, email, meeting, lead_form, contact_form",
            "nullable": true
          },
          "context_type": {
            "type": "string",
            "description": "Where the interaction happened. One of: Event, CompanyContact, ClientOrganization",
            "nullable": true
          },
          "interaction_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the interaction happened (ISO8601)",
            "nullable": true
          },
          "interaction_user_id": {
            "type": "string",
            "description": "User who logged the interaction (BSON ObjectId hex)",
            "nullable": true
          }
        },
        "required": [
          "type",
          "context_type",
          "interaction_at",
          "interaction_user_id"
        ]
      },
      "Api_V3_Entities_ActionSuggestion_Projection": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_ActionSuggestion"
            },
            "description": "The projected rows, capped by the caller's max_*"
          },
          "total_items": {
            "type": "integer",
            "format": "int32",
            "description": "True total for this parent. total_items > data.length means the cap was hit"
          }
        },
        "required": [
          "data",
          "total_items"
        ]
      },
      "Api_V3_Entities_ActionSuggestion": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Suggestion id (BSON ObjectId hex)"
          },
          "suggestion_type": {
            "type": "string",
            "description": "Suggestion kind. One of: followup_unconverted_lead",
            "nullable": true
          },
          "status": {
            "type": "string",
            "description": "Lifecycle status (pending, live, accepted, rejected, stale). Always \"live\" today — only live, unexpired suggestions are loaded.",
            "nullable": true
          },
          "reason": {
            "type": "string",
            "description": "Why the follow-up is suggested (long form)",
            "nullable": true
          },
          "short_reason": {
            "type": "string",
            "description": "Why the follow-up is suggested (one line, for a badge or banner)",
            "nullable": true
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the suggestion stops being offered (ISO8601)",
            "nullable": true
          }
        },
        "required": [
          "id",
          "suggestion_type",
          "status",
          "reason",
          "short_reason",
          "expires_at"
        ]
      },
      "Api_V3_Entities_WorkspaceMembership_Projection": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_WorkspaceMembership"
            },
            "description": "The projected rows, capped by the caller's max_*"
          },
          "total_items": {
            "type": "integer",
            "format": "int32",
            "description": "True total for this parent. total_items > data.length means the cap was hit"
          }
        },
        "required": [
          "data",
          "total_items"
        ]
      },
      "Api_V3_Entities_WorkspaceMembership": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Workspace id (BSON ObjectId hex)"
          },
          "project_id": {
            "type": "string",
            "description": "Project (Event) this workspace wraps (BSON ObjectId hex)",
            "nullable": true
          },
          "project_name": {
            "type": "string",
            "description": "Project display name",
            "nullable": true
          },
          "pipeline": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_WorkspacePipelineStage"
              }
            ],
            "description": "PER-VIEWER. Where this workspace sits in the calling company's pipeline; null when the workspace has no stage for that company.",
            "nullable": true
          },
          "archived_reason": {
            "type": "string",
            "description": "PER-VIEWER. Why the project is blocked/archived for the caller, when it is.",
            "nullable": true
          },
          "is_archived": {
            "type": "boolean",
            "description": "PER-VIEWER. Whether the caller has archived this project for themselves."
          },
          "kind": {
            "type": "string",
            "enum": [
              "client",
              "vendor"
            ],
            "description": "Party kind of the contact in this workspace (lowercase snake_case enum: client, vendor)",
            "nullable": true
          },
          "members": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_UserSummary"
            },
            "description": "Everyone on the project (vendors and clients)"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Creation time (ISO8601)"
          },
          "user_type": {
            "type": "string",
            "enum": [
              "client",
              "vendor"
            ],
            "description": "Deprecated: use kind.",
            "nullable": true
          },
          "pipeline_stage": {
            "type": "string",
            "description": "Deprecated: use pipeline. PER-VIEWER display name of the stage this project sits in for the caller.",
            "nullable": true
          }
        },
        "required": [
          "id",
          "project_id",
          "project_name",
          "pipeline",
          "archived_reason",
          "is_archived",
          "kind",
          "members",
          "created_at",
          "user_type",
          "pipeline_stage"
        ]
      },
      "Api_V3_Entities_WorkspacePipelineStage": {
        "type": "object",
        "properties": {
          "stage_id": {
            "type": "string",
            "description": "Current pipeline stage id for the calling company (matches a PipelineStageCount.stage_id from getPipelineCounts); null when the workspace has no stage for that company",
            "nullable": true
          },
          "moved_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the workspace entered its current stage (ISO8601)",
            "nullable": true
          },
          "tracked": {
            "type": "boolean",
            "description": "Whether pipeline tracking is on for the CALLING USER (the bare-positive of the stored disable_tracking). A caller that turned tracking off sees false even while a teammate still tracks the workspace."
          }
        },
        "required": [
          "stage_id",
          "moved_at",
          "tracked"
        ]
      },
      "Api_V3_Entities_Tag_Projection": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_Tag"
            },
            "description": "The projected rows, capped by the caller's max_*"
          },
          "total_items": {
            "type": "integer",
            "format": "int32",
            "description": "True total for this parent. total_items > data.length means the cap was hit"
          }
        },
        "required": [
          "data",
          "total_items"
        ]
      },
      "Api_V3_Entities_Tag": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Tag id (BSON ObjectId hex)"
          },
          "company_id": {
            "type": "string",
            "description": "Owning company id (BSON ObjectId hex)"
          },
          "name": {
            "type": "string",
            "description": "Tag display name"
          },
          "color": {
            "type": "string",
            "description": "Tag color (hex string, e.g. #EDE1D9)"
          },
          "object_type": {
            "type": "string",
            "description": "Entity kind this tag is scoped to, if any (lowercase snake_case enum: project, contact)",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Creation time (ISO8601)"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601)"
          }
        },
        "required": [
          "id",
          "company_id",
          "name",
          "color",
          "object_type",
          "created_at",
          "updated_at"
        ]
      },
      "Api_V3_Entities_ClientOrganizationSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Client organization id (BSON ObjectId hex)"
          },
          "name": {
            "type": "string",
            "description": "Organization name",
            "nullable": true
          },
          "website_url": {
            "type": "string",
            "description": "Website URL",
            "nullable": true
          },
          "phone_number": {
            "type": "string",
            "description": "Phone number",
            "nullable": true
          }
        },
        "required": [
          "id",
          "name",
          "website_url",
          "phone_number"
        ]
      },
      "Api_V3_Entities_ContactEnrichment": {
        "type": "object",
        "properties": {
          "industry": {
            "type": "string",
            "description": "The person's industry",
            "nullable": true
          },
          "company_size": {
            "type": "string",
            "description": "Size of the person's business, as a label (e.g. 1-10)",
            "nullable": true
          },
          "instagram": {
            "type": "string",
            "description": "Instagram handle or URL",
            "nullable": true
          },
          "instagram_followers": {
            "type": "integer",
            "format": "int32",
            "description": "Instagram follower count",
            "nullable": true
          },
          "facebook": {
            "type": "string",
            "description": "Facebook page URL",
            "nullable": true
          },
          "twitter": {
            "type": "string",
            "description": "Twitter / X handle or URL",
            "nullable": true
          },
          "twitter_followers": {
            "type": "integer",
            "format": "int32",
            "description": "Twitter / X follower count",
            "nullable": true
          },
          "linkedin_personal": {
            "type": "string",
            "description": "The person's LinkedIn URL",
            "nullable": true
          },
          "linkedin_business": {
            "type": "string",
            "description": "The business's LinkedIn URL",
            "nullable": true
          },
          "specialties": {
            "type": "string",
            "description": "What the business specialises in",
            "nullable": true
          },
          "founded": {
            "type": "integer",
            "format": "int32",
            "description": "Year the business was founded",
            "nullable": true
          },
          "enriched": {
            "type": "boolean",
            "description": "Whether an enrichment run for this person completed successfully (the condition under which v2 sent its client_enrichment object). False while a run is pending, failed, or was never requested."
          },
          "reaction": {
            "type": "string",
            "enum": [
              "like",
              "dislike",
              "initial"
            ],
            "description": "The member's reaction to the enrichment, recorded through the v2 enrichment_reaction action. One of: like, dislike, initial; null when no reaction was recorded.",
            "nullable": true
          }
        },
        "required": [
          "industry",
          "company_size",
          "instagram",
          "instagram_followers",
          "facebook",
          "twitter",
          "twitter_followers",
          "linkedin_personal",
          "linkedin_business",
          "specialties",
          "founded",
          "enriched",
          "reaction"
        ]
      },
      "Api_V3_Entities_CustomFieldValue_Projection": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_CustomFieldValue"
            },
            "description": "The projected rows, capped by the caller's max_*"
          },
          "total_items": {
            "type": "integer",
            "format": "int32",
            "description": "True total for this parent. total_items > data.length means the cap was hit"
          }
        },
        "required": [
          "data",
          "total_items"
        ]
      },
      "Api_V3_Entities_CustomFieldValue": {
        "description": "Api_V3_Entities_CustomFieldValue model",
        "oneOf": [
          {
            "$ref": "#/components/schemas/Api_V3_Entities_CustomFieldValue_Date"
          },
          {
            "$ref": "#/components/schemas/Api_V3_Entities_CustomFieldValue_Link"
          },
          {
            "$ref": "#/components/schemas/Api_V3_Entities_CustomFieldValue_LongText"
          },
          {
            "$ref": "#/components/schemas/Api_V3_Entities_CustomFieldValue_MultiSelect"
          },
          {
            "$ref": "#/components/schemas/Api_V3_Entities_CustomFieldValue_Number"
          },
          {
            "$ref": "#/components/schemas/Api_V3_Entities_CustomFieldValue_SingleSelect"
          },
          {
            "$ref": "#/components/schemas/Api_V3_Entities_CustomFieldValue_Text"
          }
        ]
      },
      "updateContact": {
        "type": "object",
        "properties": {
          "first_name": {
            "type": "string"
          },
          "last_name": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "phone_number": {
            "type": "string"
          },
          "address": {
            "type": "string",
            "description": "Mailing address (flat string)"
          },
          "website_url": {
            "type": "string"
          },
          "company_name": {
            "type": "string"
          },
          "job_title": {
            "type": "string"
          },
          "company_type": {
            "type": "string",
            "description": "Contact's business kind (snake_case enum)"
          },
          "private_notes": {
            "type": "string",
            "description": "Private note (per-viewer; stored against the caller)"
          },
          "preferred": {
            "type": "boolean",
            "description": "Mark/unmark as a preferred vendor (plain flag, no side effect)"
          },
          "client_organization": {
            "type": "object",
            "description": "Move the linked client into the company's client organization with this name, creating the organization if it does not exist yet (case-insensitive match within the company); the fields other than name are written only when it is created. Omit to leave the organization untouched — there is no clear-by-blank, detaching a client from its organization is not part of this endpoint. Ignored for a vendor contact. 400 when the client is the only member of its current organization or has active projects there.",
            "properties": {
              "name": {
                "type": "string",
                "description": "Organization name — the natural key within the company"
              },
              "phone_number": {
                "type": "string"
              },
              "website_url": {
                "type": "string"
              },
              "address": {
                "type": "string",
                "description": "Mailing address (flat string)"
              },
              "company_type": {
                "type": "string",
                "description": "The organization's business kind (snake_case enum)"
              },
              "private_notes": {
                "type": "string",
                "description": "Private note on the organization"
              }
            },
            "required": [
              "name"
            ]
          },
          "sms_consent_confirmed": {
            "type": "boolean",
            "description": "The member confirms this client consented to SMS. true records the consent against phone_number when sent in the same request, else against the phone number already on the contact (400 if there is neither); false revokes any existing consent. Omit to leave consent untouched. Client contacts only."
          },
          "custom_fields": {
            "type": "array",
            "description": "Values for the company's custom fields of this record's kind. MERGE, not replace: only the listed fields are written, the rest keep their value. Each entry is validated like `PATCH .../custom_fields/:field_id` before anything is written: an unknown, foreign, archived or wrong-kind `field_id` is a 404; an invalid `value`, a repeated `field_id` or more than 50 entries is a 400, and nothing is written.",
            "items": {
              "type": "object",
              "properties": {
                "field_id": {
                  "type": "string",
                  "description": "Custom field id (the `id` of a GET /custom_fields row)"
                },
                "value": {
                  "type": "string",
                  "description": "The new value as a String: a number as its digits, a date as ISO8601, a single_select as the option's id, a multi_select as comma-separated option ids. `null` clears the value."
                }
              },
              "required": [
                "field_id",
                "value"
              ]
            }
          },
          "include": {
            "type": "array",
            "description": "Comma-separated relations to populate. Allowed: user, action_suggestions, workspaces, tags, client_organization, custom_fields, enrichment. A relation not requested is null. Nested paths (a.b) are not supported.",
            "items": {
              "type": "string",
              "enum": [
                "user",
                "action_suggestions",
                "workspaces",
                "tags",
                "client_organization",
                "custom_fields",
                "enrichment"
              ]
            }
          },
          "max_action_suggestions": {
            "type": "integer",
            "format": "int32",
            "description": "Max action_suggestions per row (1..25, default 3). Ordered by expires_at asc. Requires include=action_suggestions.",
            "minimum": 1,
            "maximum": 25
          },
          "max_workspaces": {
            "type": "integer",
            "format": "int32",
            "description": "Max workspaces per row (1..25, default 3). Ordered by _id desc. Requires include=workspaces.",
            "minimum": 1,
            "maximum": 25
          },
          "max_tags": {
            "type": "integer",
            "format": "int32",
            "description": "Max tags per row (1..25, default 25). Ordered by name asc. Requires include=tags.",
            "minimum": 1,
            "maximum": 25
          },
          "max_custom_fields": {
            "type": "integer",
            "format": "int32",
            "description": "Max custom_fields per row (1..50, default 50). Ordered by order asc. Requires include=custom_fields.",
            "minimum": 1,
            "maximum": 50
          }
        },
        "description": "Update a contact (partial; data fields only)"
      },
      "deleteContact": {
        "type": "object",
        "properties": {
          "reaction_text": {
            "type": "string",
            "description": "Why the member is deleting this contact. Recorded as a dislike Reaction when the contact came from an AI lead suggestion (user_source ai_lead_suggestion); ignored otherwise."
          }
        },
        "description": "Delete a contact"
      },
      "updateContactInteraction": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "How the interaction happened (manual, email, meeting, lead_form, contact_form)",
            "enum": [
              "manual",
              "email",
              "meeting",
              "lead_form",
              "contact_form"
            ]
          },
          "context_type": {
            "type": "string",
            "description": "Where the interaction happened (Event, CompanyContact, ClientOrganization)",
            "enum": [
              "Event",
              "CompanyContact",
              "ClientOrganization"
            ]
          },
          "interaction_date": {
            "type": "string",
            "format": "date-time",
            "description": "When the interaction happened (ISO8601)"
          },
          "include": {
            "type": "array",
            "description": "Comma-separated relations to populate. Allowed: user, action_suggestions, workspaces, tags, client_organization, custom_fields, enrichment. A relation not requested is null. Nested paths (a.b) are not supported.",
            "items": {
              "type": "string",
              "enum": [
                "user",
                "action_suggestions",
                "workspaces",
                "tags",
                "client_organization",
                "custom_fields",
                "enrichment"
              ]
            }
          },
          "max_action_suggestions": {
            "type": "integer",
            "format": "int32",
            "description": "Max action_suggestions per row (1..25, default 3). Ordered by expires_at asc. Requires include=action_suggestions.",
            "minimum": 1,
            "maximum": 25
          },
          "max_workspaces": {
            "type": "integer",
            "format": "int32",
            "description": "Max workspaces per row (1..25, default 3). Ordered by _id desc. Requires include=workspaces.",
            "minimum": 1,
            "maximum": 25
          },
          "max_tags": {
            "type": "integer",
            "format": "int32",
            "description": "Max tags per row (1..25, default 25). Ordered by name asc. Requires include=tags.",
            "minimum": 1,
            "maximum": 25
          },
          "max_custom_fields": {
            "type": "integer",
            "format": "int32",
            "description": "Max custom_fields per row (1..50, default 50). Ordered by order asc. Requires include=custom_fields.",
            "minimum": 1,
            "maximum": 50
          }
        },
        "description": "Set (replace) a contact's last interaction"
      },
      "addContactTag": {
        "type": "object",
        "properties": {
          "include": {
            "type": "array",
            "description": "Comma-separated relations to populate. Allowed: user, action_suggestions, workspaces, tags, client_organization, custom_fields, enrichment. A relation not requested is null. Nested paths (a.b) are not supported.",
            "items": {
              "type": "string",
              "enum": [
                "user",
                "action_suggestions",
                "workspaces",
                "tags",
                "client_organization",
                "custom_fields",
                "enrichment"
              ]
            }
          },
          "max_action_suggestions": {
            "type": "integer",
            "format": "int32",
            "description": "Max action_suggestions per row (1..25, default 3). Ordered by expires_at asc. Requires include=action_suggestions.",
            "minimum": 1,
            "maximum": 25
          },
          "max_workspaces": {
            "type": "integer",
            "format": "int32",
            "description": "Max workspaces per row (1..25, default 3). Ordered by _id desc. Requires include=workspaces.",
            "minimum": 1,
            "maximum": 25
          },
          "max_tags": {
            "type": "integer",
            "format": "int32",
            "description": "Max tags per row (1..25, default 25). Ordered by name asc. Requires include=tags.",
            "minimum": 1,
            "maximum": 25
          },
          "max_custom_fields": {
            "type": "integer",
            "format": "int32",
            "description": "Max custom_fields per row (1..50, default 50). Ordered by order asc. Requires include=custom_fields.",
            "minimum": 1,
            "maximum": 50
          }
        },
        "description": "Tag a contact (idempotent)"
      },
      "Api_V3_Entities_CustomFieldValue_Page": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_CustomFieldValue"
            },
            "description": "The rows on this page (empty when nothing matched)"
          },
          "pagination": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_Pagination"
              }
            ],
            "description": "Where this page sits in the full result set"
          }
        },
        "required": [
          "data",
          "pagination"
        ],
        "description": "Api_V3_Entities_CustomFieldValue_Page model"
      },
      "Api_V3_Entities_Pagination": {
        "type": "object",
        "properties": {
          "page": {
            "type": "integer",
            "format": "int32",
            "description": "1-indexed number of the page returned (echoes the request)"
          },
          "per_page": {
            "type": "integer",
            "format": "int32",
            "description": "Page size (echoes the request)"
          },
          "total_items": {
            "type": "integer",
            "format": "int32",
            "description": "Total rows matching the query, across all pages"
          },
          "total_pages": {
            "type": "integer",
            "format": "int32",
            "description": "Total number of pages (0 when nothing matched)"
          },
          "last_page": {
            "type": "boolean",
            "description": "True when this is the final page — stop paging"
          },
          "offset": {
            "type": "integer",
            "format": "int32",
            "description": "Rows skipped before this page ((page - 1) * per_page)"
          }
        },
        "required": [
          "page",
          "per_page",
          "total_items",
          "total_pages",
          "last_page",
          "offset"
        ]
      },
      "updateContactCustomField": {
        "type": "object",
        "properties": {
          "value": {
            "type": "string",
            "description": "The new value, as a String — see the operation description"
          }
        },
        "required": [
          "value"
        ],
        "description": "Set a contact's value for one custom field"
      },
      "Api_V3_Entities_CustomField_Page": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_CustomField"
            },
            "description": "The rows on this page (empty when nothing matched)"
          },
          "pagination": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_Pagination"
              }
            ],
            "description": "Where this page sits in the full result set"
          }
        },
        "required": [
          "data",
          "pagination"
        ],
        "description": "Api_V3_Entities_CustomField_Page model"
      },
      "Api_V3_Entities_CustomField": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Custom field id (BSON ObjectId hex)"
          },
          "company_id": {
            "type": "string",
            "description": "Owning company id (BSON ObjectId hex)"
          },
          "name": {
            "type": "string",
            "description": "Field display name, as the member defined it",
            "nullable": true
          },
          "entity_type": {
            "type": "string",
            "enum": [
              "project",
              "contact"
            ],
            "description": "Which kind of record this field appears on (lowercase snake_case enum: project, contact)"
          },
          "type": {
            "type": "string",
            "enum": [
              "text",
              "long_text",
              "date",
              "number",
              "link",
              "single_select",
              "multi_select"
            ],
            "description": "The kind of value this field holds (lowercase snake_case enum) — the discriminator of the CustomFieldValue union returned under a record"
          },
          "order": {
            "type": "integer",
            "format": "int32",
            "description": "Position in the member's own ordering of their fields (ascending)",
            "nullable": true
          },
          "visible_to_clients": {
            "type": "boolean",
            "description": "Whether the field is shown to the member's clients, not only to their team"
          },
          "archived": {
            "type": "boolean",
            "description": "Whether the member has deleted this field. An archived field is read-only and shows on a record only when that record holds a value for it; restore with POST /custom_fields/:id/restore"
          },
          "options": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_CustomFieldOption"
            },
            "description": "The choices a single_select / multi_select field offers; `[]` for every other type"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Creation time (ISO8601). null for a field created before the schema collection recorded timestamps",
            "nullable": true
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601). null for a field never edited since it was created",
            "nullable": true
          }
        },
        "required": [
          "id",
          "company_id",
          "name",
          "entity_type",
          "type",
          "order",
          "visible_to_clients",
          "archived",
          "options",
          "created_at",
          "updated_at"
        ],
        "description": "Api_V3_Entities_CustomField model"
      },
      "createCustomField": {
        "type": "object",
        "properties": {
          "entity_type": {
            "type": "string",
            "description": "Which kind of record the field appears on. One of: project, contact",
            "enum": [
              "project",
              "contact"
            ]
          },
          "name": {
            "type": "string",
            "description": "Field display name"
          },
          "type": {
            "type": "string",
            "description": "The kind of value the field holds. One of: text, long_text, date, number, link, single_select, multi_select",
            "enum": [
              "text",
              "long_text",
              "date",
              "number",
              "link",
              "single_select",
              "multi_select"
            ]
          },
          "order": {
            "type": "integer",
            "format": "int32",
            "description": "Position in the member's ordering of their fields (ascending). Defaults to after the last live field of the same `entity_type`"
          },
          "visible_to_clients": {
            "type": "boolean",
            "description": "Whether clients see the field, not only the member's team. Cannot be null"
          },
          "options": {
            "type": "array",
            "description": "The choices offered. Only meaningful for single_select / multi_select",
            "items": {
              "type": "object",
              "properties": {
                "label": {
                  "type": "string",
                  "description": "Option display label"
                },
                "color": {
                  "type": "string",
                  "description": "Option color (hex string, e.g. #EDE1D9)"
                }
              },
              "required": [
                "label"
              ]
            }
          }
        },
        "required": [
          "entity_type",
          "name",
          "type"
        ],
        "description": "Create a custom field definition"
      },
      "updateCustomField": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Field display name"
          },
          "order": {
            "type": "integer",
            "format": "int32"
          },
          "visible_to_clients": {
            "type": "boolean",
            "description": "Cannot be null"
          },
          "options": {
            "type": "array",
            "description": "Replaces the whole option list. Only meaningful for select fields",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "description": "An existing option's id — keeps it, and every selection of it. Omit to add a new option"
                },
                "label": {
                  "type": "string",
                  "description": "Option display label"
                },
                "color": {
                  "type": "string",
                  "description": "Option color (hex string, e.g. #EDE1D9)"
                }
              },
              "required": [
                "label"
              ]
            }
          }
        },
        "description": "Update a custom field definition (partial)"
      },
      "Api_V3_Entities_Inquiry_Page": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_Inquiry"
            },
            "description": "The rows on this page (empty when nothing matched)"
          },
          "pagination": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_Pagination"
              }
            ],
            "description": "Where this page sits in the full result set"
          }
        },
        "required": [
          "data",
          "pagination"
        ],
        "description": "Api_V3_Entities_Inquiry_Page model"
      },
      "Api_V3_Entities_Inquiry": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Inquiry id (BSON ObjectId hex)"
          },
          "source": {
            "type": "string",
            "enum": [
              "contact_form",
              "lead_form",
              "scheduler",
              "api",
              "unknown"
            ],
            "description": "Surface the inquiry was created through; 'unknown' when none was recorded"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "processed",
              "dropped"
            ],
            "description": "Processing status: pending (project and contact not built yet), processed, dropped (screened out, no project)"
          },
          "contact_id": {
            "type": "string",
            "description": "Contact (CompanyContact) id; null until processed or once the contact is deleted",
            "nullable": true
          },
          "contact": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_Contact"
              }
            ],
            "description": "The inquiry's contact. null unless ?include=contact, and null when the contact is out of reach (deleted, or not created by the caller's partner under partner_only=true).",
            "nullable": true
          },
          "project_id": {
            "type": "string",
            "description": "Project (Event) id; null until processed",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the inquiry was received (ISO8601)"
          }
        },
        "required": [
          "id",
          "source",
          "status",
          "contact_id",
          "contact",
          "project_id",
          "created_at"
        ],
        "description": "Api_V3_Entities_Inquiry model"
      },
      "createInquiry": {
        "type": "object",
        "properties": {
          "contact": {
            "type": "object",
            "description": "The person submitting the inquiry",
            "properties": {
              "email": {
                "type": "string",
                "description": "Contact email (the natural key within a company)"
              },
              "full_name": {
                "type": "string",
                "maxLength": 200
              },
              "phone_number": {
                "type": "string",
                "maxLength": 200
              },
              "custom_fields": {
                "type": "array",
                "description": "Values for the company's custom fields of this record's kind. MERGE, not replace: only the listed fields are written, the rest keep their value. Each entry is validated like `PATCH .../custom_fields/:field_id` before anything is written: an unknown, foreign, archived or wrong-kind `field_id` is a 404; an invalid `value`, a repeated `field_id` or more than 50 entries is a 400, and nothing is written.",
                "items": {
                  "type": "object",
                  "properties": {
                    "field_id": {
                      "type": "string",
                      "description": "Custom field id (the `id` of a GET /custom_fields row)"
                    },
                    "value": {
                      "type": "string",
                      "description": "The new value as a String: a number as its digits, a date as ISO8601, a single_select as the option's id, a multi_select as comma-separated option ids. `null` clears the value."
                    }
                  },
                  "required": [
                    "field_id",
                    "value"
                  ]
                }
              }
            },
            "required": [
              "email"
            ]
          },
          "project": {
            "type": "object",
            "description": "Details of the project the inquiry is about",
            "properties": {
              "name": {
                "type": "string",
                "description": "Project display name (auto-generated if omitted)",
                "maxLength": 100
              },
              "project_type_id": {
                "type": "string",
                "description": "Id of one of the company's project types"
              },
              "project_date": {
                "type": "string",
                "format": "date",
                "description": "Primary start calendar date"
              },
              "project_details": {
                "type": "string",
                "description": "Free-text project details",
                "maxLength": 5000
              },
              "project_location": {
                "type": "string",
                "description": "Primary location/venue",
                "maxLength": 200
              },
              "guest_count": {
                "type": "integer",
                "format": "int32",
                "description": "Expected number of guests",
                "minimum": 0,
                "maximum": 100000000
              },
              "budget": {
                "type": "integer",
                "format": "int32",
                "description": "Expected budget, a bare number in the company's currency"
              },
              "services": {
                "type": "array",
                "description": "Services the contact is interested in",
                "items": {
                  "type": "string"
                },
                "maxItems": 20
              },
              "lead_source_id": {
                "type": "string",
                "description": "Id of one of the company's lead sources (\"how did you hear about us\")"
              },
              "lead_source_open_text": {
                "type": "string",
                "description": "Free text for an \"other\" lead source",
                "maxLength": 200
              },
              "custom_fields": {
                "type": "array",
                "description": "Values for the company's custom fields of this record's kind. MERGE, not replace: only the listed fields are written, the rest keep their value. Each entry is validated like `PATCH .../custom_fields/:field_id` before anything is written: an unknown, foreign, archived or wrong-kind `field_id` is a 404; an invalid `value`, a repeated `field_id` or more than 50 entries is a 400, and nothing is written.",
                "items": {
                  "type": "object",
                  "properties": {
                    "field_id": {
                      "type": "string",
                      "description": "Custom field id (the `id` of a GET /custom_fields row)"
                    },
                    "value": {
                      "type": "string",
                      "description": "The new value as a String: a number as its digits, a date as ISO8601, a single_select as the option's id, a multi_select as comma-separated option ids. `null` clears the value."
                    }
                  },
                  "required": [
                    "field_id",
                    "value"
                  ]
                }
              }
            }
          },
          "merge_into_existing_project": {
            "type": "boolean",
            "description": "Add the contact to its existing open project instead of creating a new one",
            "default": false
          }
        },
        "required": [
          "contact"
        ],
        "description": "Submit an inquiry"
      },
      "Api_V3_Entities_AsyncTask": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "AsyncTask id (BSON ObjectId hex)"
          },
          "task_type": {
            "type": "string",
            "description": "The operation that produced this task (e.g. \"pay_link.create\")"
          },
          "status": {
            "type": "string",
            "description": "Task lifecycle status (enum). One of: pending, succeeded, failed"
          },
          "result_resource_type": {
            "type": "string",
            "description": "On success, the kind of the produced/affected resource (e.g. \"pay_link\"). Null while pending, or when the task yields no resource.",
            "nullable": true
          },
          "result_resource_id": {
            "type": "string",
            "description": "On success, the id of the result resource — fetch it via that domain's typed GET. Null otherwise.",
            "nullable": true
          },
          "failure_reason": {
            "type": "string",
            "description": "Set when status = failed; a user-safe reason. Null otherwise.",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Creation time (ISO8601)"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601)"
          }
        },
        "required": [
          "id",
          "task_type",
          "status",
          "result_resource_type",
          "result_resource_id",
          "failure_reason",
          "created_at",
          "updated_at"
        ],
        "description": "Api_V3_Entities_AsyncTask model"
      },
      "Api_V3_Entities_PipelineEntry_Page": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_PipelineEntry"
            },
            "description": "The rows on this page (empty when nothing matched)"
          },
          "pagination": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_Pagination"
              }
            ],
            "description": "Where this page sits in the full result set"
          }
        },
        "required": [
          "data",
          "pagination"
        ],
        "description": "Api_V3_Entities_PipelineEntry_Page model"
      },
      "Api_V3_Entities_PipelineEntry": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Workspace id (BSON ObjectId hex)"
          },
          "project_id": {
            "type": "string",
            "description": "Project (Event) id this workspace wraps (BSON ObjectId hex)",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Project name",
            "nullable": true
          },
          "project_date": {
            "type": "string",
            "format": "date",
            "description": "Project date (calendar date, no time)",
            "nullable": true
          },
          "project_end_date": {
            "type": "string",
            "format": "date",
            "description": "Project end date (calendar date, no time)",
            "nullable": true
          },
          "project_location": {
            "type": "string",
            "description": "Project location",
            "nullable": true
          },
          "project_type": {
            "type": "string",
            "description": "Project type label",
            "nullable": true
          },
          "cover_image_url": {
            "type": "string",
            "description": "Project cover image URL; null when the project has no image. A Cloudinary secure URL when the image was uploaded through Cloudinary, so a client may derive its own transformations from it",
            "nullable": true
          },
          "current_stage": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_PipelineStageRef"
              }
            ],
            "description": "The workspace's current pipeline stage (per the requested pipeline user)"
          },
          "active": {
            "type": "boolean",
            "description": "Whether the workspace is active (not archived) for the requested pipeline user(s)"
          },
          "tracked": {
            "type": "boolean",
            "description": "Whether the workspace is tracked in the pipeline (false = tracking disabled)"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Workspace tags (only when owned by the caller's company; otherwise empty)"
          },
          "member_count": {
            "type": "integer",
            "format": "int32",
            "description": "Number of members (vendors + clients)"
          },
          "has_follow_up_suggestion": {
            "type": "boolean",
            "description": "PER-VIEWER. Whether a live, unexpired follow-up suggestion exists for this workspace. Always false when the caller has follow-up suggestions disabled"
          },
          "last_activity_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last activity time (ISO8601)",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Workspace creation time (ISO8601)"
          }
        },
        "required": [
          "id",
          "project_id",
          "name",
          "project_date",
          "project_end_date",
          "project_location",
          "project_type",
          "cover_image_url",
          "current_stage",
          "active",
          "tracked",
          "tags",
          "member_count",
          "has_follow_up_suggestion",
          "last_activity_at",
          "created_at"
        ]
      },
      "Api_V3_Entities_PipelineStageRef": {
        "type": "object",
        "properties": {
          "stage_id": {
            "type": "string",
            "description": "Current pipeline stage id (matches a PipelineStageCount.stage_id from getPipelineCounts); null when untracked",
            "nullable": true
          },
          "moved_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the workspace entered its current stage (ISO8601); null when untracked",
            "nullable": true
          }
        },
        "required": [
          "stage_id",
          "moved_at"
        ]
      },
      "Api_V3_Entities_PipelineCounts": {
        "type": "object",
        "properties": {
          "active_count": {
            "type": "integer",
            "format": "int32",
            "description": "Total active (tracked, not archived) workspaces"
          },
          "archived_count": {
            "type": "integer",
            "format": "int32",
            "description": "Total archived workspaces"
          },
          "untracked_count": {
            "type": "integer",
            "format": "int32",
            "description": "Total tracking-disabled (untracked) workspaces"
          },
          "categories": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_PipelineCategoryCount"
            },
            "description": "Per-category tallies (lead, booked, other)"
          },
          "stages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_PipelineStageCount"
            },
            "description": "Per-stage tallies, ordered by the stage's display order"
          }
        },
        "required": [
          "active_count",
          "archived_count",
          "untracked_count",
          "categories",
          "stages"
        ],
        "description": "Api_V3_Entities_PipelineCounts model"
      },
      "Api_V3_Entities_PipelineCategoryCount": {
        "type": "object",
        "properties": {
          "category": {
            "type": "string",
            "description": "Stage category (lowercase snake_case enum: lead, booked, other)"
          },
          "active_count": {
            "type": "integer",
            "format": "int32",
            "description": "Active (not archived) workspaces in this category"
          },
          "archived_count": {
            "type": "integer",
            "format": "int32",
            "description": "Archived workspaces in this category"
          }
        },
        "required": [
          "category",
          "active_count",
          "archived_count"
        ]
      },
      "Api_V3_Entities_PipelineStageCount": {
        "type": "object",
        "properties": {
          "stage_id": {
            "type": "string",
            "description": "Pipeline stage id (BSON ObjectId hex)"
          },
          "name": {
            "type": "string",
            "description": "Stage display name (server-localized for built-in stages; the author-supplied name for custom ones)",
            "nullable": true
          },
          "system_key": {
            "type": "string",
            "description": "Stable key of a built-in stage (e.g. '_INQUIRY_'); null for a company's custom stage. Lets a client localize the stage itself instead of using `name`",
            "nullable": true
          },
          "category": {
            "type": "string",
            "description": "Stage category (lowercase snake_case enum: lead, booked, other)",
            "nullable": true
          },
          "group": {
            "type": "string",
            "description": "Stage group (lowercase snake_case enum: opportunities, projects)",
            "nullable": true
          },
          "order": {
            "type": "number",
            "format": "float",
            "description": "Display order (float; gaps allow insertion between stages)",
            "nullable": true
          },
          "active_count": {
            "type": "integer",
            "format": "int32",
            "description": "Active (not archived) workspaces in this stage"
          },
          "archived_count": {
            "type": "integer",
            "format": "int32",
            "description": "Archived workspaces in this stage"
          }
        },
        "required": [
          "stage_id",
          "name",
          "system_key",
          "category",
          "group",
          "order",
          "active_count",
          "archived_count"
        ]
      },
      "Api_V3_Entities_Workspace_Page": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_Workspace"
            },
            "description": "The rows on this page (empty when nothing matched)"
          },
          "pagination": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_Pagination"
              }
            ],
            "description": "Where this page sits in the full result set"
          }
        },
        "required": [
          "data",
          "pagination"
        ],
        "description": "Api_V3_Entities_Workspace_Page model"
      },
      "Api_V3_Entities_Workspace": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Workspace id (BSON ObjectId hex)"
          },
          "project_id": {
            "type": "string",
            "description": "Project (Event) id this workspace wraps (BSON ObjectId hex)",
            "nullable": true
          },
          "name": {
            "type": "string",
            "description": "Workspace tab name",
            "nullable": true
          },
          "kind": {
            "type": "string",
            "description": "Workspace kind (lowercase snake_case enum: general, team, design, all_vendors, timeline — almost always general)",
            "nullable": true
          },
          "status": {
            "type": "string",
            "description": "Lifecycle status (lowercase snake_case enum: lead, lead_sent, lead_archived, client, client_archived)",
            "nullable": true
          },
          "source": {
            "type": "string",
            "description": "How the workspace originated (lowercase snake_case enum: manual, google, widget, company_team, vendor_referral, ...)",
            "nullable": true
          },
          "archived": {
            "type": "boolean",
            "description": "Whether the workspace is archived for the owning company (a team member archived it)"
          },
          "inactive_user_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "User ids for whom this workspace is archived — a caller in this list should treat the workspace as archived regardless of `archived` (BSON ObjectId hex)"
          },
          "creator_id": {
            "type": "string",
            "description": "User id of the workspace creator (BSON ObjectId hex)",
            "nullable": true
          },
          "creator_company_id": {
            "type": "string",
            "description": "Company that owns this workspace — the creator's company at creation time (BSON ObjectId hex)",
            "nullable": true
          },
          "member_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "User ids of this workspace's members — both vendors (the company team) and clients (BSON ObjectId hex)"
          },
          "tag_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Tag ids attached to this workspace (BSON ObjectId hex)",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Creation time (ISO8601)"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601)"
          },
          "creator": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_UserSummary"
              }
            ],
            "description": "The person who created the workspace. null unless ?include=creator",
            "nullable": true
          },
          "pipeline_stage": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_WorkspacePipelineStage"
              }
            ],
            "description": "Where this workspace sits in the calling company's pipeline. null unless ?include=pipeline_stage (always populated inside a project's `workspaces`), and also null when the workspace has no stage for that company. PER-VIEWER — see the entity.",
            "nullable": true
          },
          "automations": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_WorkspaceAutomations"
              }
            ],
            "description": "Which automations generation governs this workspace. null unless ?include=automations",
            "nullable": true
          },
          "action_suggestions": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_ActionSuggestion_Projection"
              }
            ],
            "description": "Live follow-up suggestions for this workspace, soonest expiry first. null unless ?include=action_suggestions; `{ data: [], total_items: 0 }` when there are none. `total_items` is the true total, so total_items > data.length means max_action_suggestions truncated it.",
            "nullable": true
          },
          "scheduled_sessions": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_WorkspaceScheduledSession_Projection"
              }
            ],
            "description": "Upcoming meetings on this workspace, earliest first. null unless ?include=scheduled_sessions; `{ data: [], total_items: 0 }` when there are none. Caller-relative: the rows come from the caller's own calendar, so two members of one workspace can legitimately see different sets.",
            "nullable": true
          }
        },
        "required": [
          "id",
          "project_id",
          "name",
          "kind",
          "status",
          "source",
          "archived",
          "inactive_user_ids",
          "creator_id",
          "creator_company_id",
          "member_ids",
          "tag_ids",
          "created_at",
          "updated_at",
          "creator",
          "pipeline_stage",
          "automations",
          "action_suggestions",
          "scheduled_sessions"
        ],
        "description": "Api_V3_Entities_Workspace model"
      },
      "Api_V3_Entities_WorkspaceAutomations": {
        "type": "object",
        "properties": {
          "mode": {
            "type": "string",
            "description": "Which automations generation applies to this workspace (lowercase snake_case enum: old, new). `old` when a v1 workflow is still pending on the workspace, otherwise whichever generation the creator's account is on.",
            "nullable": true
          }
        },
        "required": [
          "mode"
        ]
      },
      "Api_V3_Entities_WorkspaceScheduledSession_Projection": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_WorkspaceScheduledSession"
            },
            "description": "The projected rows, capped by the caller's max_*"
          },
          "total_items": {
            "type": "integer",
            "format": "int32",
            "description": "True total for this parent. total_items > data.length means the cap was hit"
          }
        },
        "required": [
          "data",
          "total_items"
        ]
      },
      "Api_V3_Entities_WorkspaceScheduledSession": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Session id (BSON ObjectId hex)"
          },
          "title": {
            "type": "string",
            "description": "Session title. Group-session titles have the client name stripped by the server.",
            "nullable": true
          },
          "date_time_start": {
            "type": "string",
            "format": "date-time",
            "description": "Start of the session (ISO8601)",
            "nullable": true
          },
          "date_time_end": {
            "type": "string",
            "format": "date-time",
            "description": "End of the session (ISO8601)",
            "nullable": true
          },
          "date_start": {
            "type": "string",
            "format": "date",
            "description": "Calendar date for an all-day session (ISO8601)",
            "nullable": true
          },
          "date_end": {
            "type": "string",
            "format": "date",
            "description": "End calendar date for a multi-day all-day session (ISO8601)",
            "nullable": true
          },
          "all_day": {
            "type": "boolean",
            "description": "Whether the session occupies the whole day"
          },
          "flow_id": {
            "type": "string",
            "description": "Smart file that booked this session (BSON ObjectId hex)",
            "nullable": true
          }
        },
        "required": [
          "id",
          "title",
          "date_time_start",
          "date_time_end",
          "date_start",
          "date_end",
          "all_day",
          "flow_id"
        ]
      },
      "Api_V3_Entities_WorkspaceCounts": {
        "type": "object",
        "properties": {
          "all": {
            "type": "integer",
            "format": "int32",
            "description": "Total workspaces the caller's company owns (== listWorkspaces total_items)"
          },
          "active": {
            "type": "integer",
            "format": "int32",
            "description": "Company workspaces that are not archived (== listWorkspaces?archived=false)"
          },
          "inactive": {
            "type": "integer",
            "format": "int32",
            "description": "Company workspaces that are archived (== listWorkspaces?archived=true)"
          }
        },
        "required": [
          "all",
          "active",
          "inactive"
        ],
        "description": "Api_V3_Entities_WorkspaceCounts model"
      },
      "Api_V3_Entities_WorkspaceExistence": {
        "type": "object",
        "properties": {
          "has_any": {
            "type": "boolean",
            "description": "True if the caller's company owns at least one workspace"
          }
        },
        "required": [
          "has_any"
        ],
        "description": "Api_V3_Entities_WorkspaceExistence model"
      },
      "Api_V3_Entities_WorkspaceDeletable": {
        "type": "object",
        "properties": {
          "deletable": {
            "type": "boolean",
            "description": "Whether the workspace (and all its files/flows) can be deleted by the caller"
          },
          "reason": {
            "type": "string",
            "enum": [
              "not_permitted",
              "has_undeletable_files"
            ],
            "description": "Why not, when deletable is false; null otherwise. not_permitted covers a client caller, a caller from another company, and a team member who is neither the creator nor a company owner/admin.",
            "nullable": true
          }
        },
        "required": [
          "deletable",
          "reason"
        ],
        "description": "Api_V3_Entities_WorkspaceDeletable model"
      },
      "updateWorkspace": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Workspace tab name"
          }
        },
        "description": "Update a workspace (partial; renames the tab)"
      },
      "Api_V3_Entities_WorkspaceMember_Page": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_WorkspaceMember"
            },
            "description": "The rows on this page (empty when nothing matched)"
          },
          "pagination": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_Pagination"
              }
            ],
            "description": "Where this page sits in the full result set"
          }
        },
        "required": [
          "data",
          "pagination"
        ],
        "description": "Api_V3_Entities_WorkspaceMember_Page model"
      },
      "Api_V3_Entities_WorkspaceMember": {
        "type": "object",
        "properties": {
          "user_id": {
            "type": "string",
            "description": "Member user id (BSON ObjectId hex)"
          },
          "kind": {
            "type": "string",
            "description": "Party kind of the member (lowercase snake_case enum: vendor, client)",
            "nullable": true
          },
          "role": {
            "type": "string",
            "description": "Workspace role (lowercase snake_case enum: vendor, host) — the creator is the host",
            "nullable": true
          },
          "status": {
            "type": "string",
            "description": "Membership status (lowercase snake_case enum: member_new, member_invite_sent, member_active)",
            "nullable": true
          },
          "added_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the member was added to the workspace (ISO8601)",
            "nullable": true
          },
          "unsubscribed": {
            "type": "boolean",
            "description": "Whether this person opted out of the workspace-owning company's commercial email"
          },
          "sms_consent_confirmed": {
            "type": "boolean",
            "description": "Whether this client member has a live SMS consent on file — the gate on texting them. False for a vendor, and when the newest consent is revoked or predates the current consent text version. NOT company-scoped (parity with v2 ClientUser#valid_sms_consent?)."
          },
          "user": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_UserSummary"
              }
            ],
            "description": "The person behind user_id — name, email, avatar, kind and company. null unless ?include=user",
            "nullable": true
          },
          "contact": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_WorkspaceMemberContact"
              }
            ],
            "description": "The calling company's contact record for this member. null unless ?include=contact, and legitimately null for a vendor team member, who has no contact record.",
            "nullable": true
          }
        },
        "required": [
          "user_id",
          "kind",
          "role",
          "status",
          "added_at",
          "unsubscribed",
          "sms_consent_confirmed",
          "user",
          "contact"
        ],
        "description": "Api_V3_Entities_WorkspaceMember model"
      },
      "Api_V3_Entities_WorkspaceMemberContact": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Contact id (BSON ObjectId hex)"
          }
        },
        "required": [
          "id"
        ]
      },
      "addWorkspaceMember": {
        "type": "object",
        "properties": {
          "include": {
            "type": "array",
            "description": "Comma-separated relations to populate. Allowed: user, contact. A relation not requested is null. Nested paths (a.b) are not supported.",
            "items": {
              "type": "string",
              "enum": [
                "user",
                "contact"
              ]
            }
          }
        },
        "description": "Add a member to a workspace (idempotent)"
      },
      "archiveWorkspace": {
        "type": "object",
        "properties": {
          "reason": {
            "type": "string",
            "description": "Free-text archive reason (recorded on the pipeline data)"
          }
        },
        "description": "Archive a workspace for the caller and their team"
      },
      "bookWorkspace": {
        "type": "object",
        "properties": {
          "include": {
            "type": "array",
            "description": "Comma-separated relations to populate. Allowed: creator, pipeline_stage, automations, action_suggestions, scheduled_sessions. A relation not requested is null. Nested paths (a.b) are not supported.",
            "items": {
              "type": "string",
              "enum": [
                "creator",
                "pipeline_stage",
                "automations",
                "action_suggestions",
                "scheduled_sessions"
              ]
            }
          },
          "max_action_suggestions": {
            "type": "integer",
            "format": "int32",
            "description": "Max action_suggestions per row (1..25, default 3). Ordered by expires_at asc. Requires include=action_suggestions.",
            "minimum": 1,
            "maximum": 25
          },
          "max_scheduled_sessions": {
            "type": "integer",
            "format": "int32",
            "description": "Max scheduled_sessions per row (1..100, default 25). Ordered by date_time_start asc. Requires include=scheduled_sessions.",
            "minimum": 1,
            "maximum": 100
          }
        },
        "description": "Book a workspace (mark the project as booked)"
      },
      "Api_V3_Entities_LeadSource_Page": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_LeadSource"
            },
            "description": "The rows on this page (empty when nothing matched)"
          },
          "pagination": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_Pagination"
              }
            ],
            "description": "Where this page sits in the full result set"
          }
        },
        "required": [
          "data",
          "pagination"
        ],
        "description": "Api_V3_Entities_LeadSource_Page model"
      },
      "Api_V3_Entities_LeadSource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "objectid",
            "description": "Lead source id (BSON ObjectId hex)"
          },
          "label": {
            "type": "string",
            "description": "Display label",
            "nullable": true
          },
          "editable": {
            "type": "boolean",
            "description": "Whether the label can be changed / the lead source deleted"
          },
          "open_text": {
            "type": "boolean",
            "description": "Whether clients are asked for free text with this lead source"
          }
        },
        "required": [
          "id",
          "label",
          "editable",
          "open_text"
        ],
        "description": "Api_V3_Entities_LeadSource model"
      },
      "createLeadSource": {
        "type": "object",
        "properties": {
          "label": {
            "type": "string",
            "description": "Display label (unique within the company, case-insensitive)"
          }
        },
        "required": [
          "label"
        ],
        "description": "Create a lead source"
      },
      "updateLeadSource": {
        "type": "object",
        "properties": {
          "label": {
            "type": "string",
            "description": "New display label"
          }
        },
        "required": [
          "label"
        ],
        "description": "Rename a lead source"
      },
      "Api_V3_Entities_Project_Page": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_Project"
            },
            "description": "The rows on this page (empty when nothing matched)"
          },
          "pagination": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_Pagination"
              }
            ],
            "description": "Where this page sits in the full result set"
          }
        },
        "required": [
          "data",
          "pagination"
        ],
        "description": "Api_V3_Entities_Project_Page model"
      },
      "Api_V3_Entities_Project": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Project id (BSON ObjectId hex)"
          },
          "name": {
            "type": "string",
            "description": "Project display name",
            "nullable": true
          },
          "project_date": {
            "type": "string",
            "format": "date",
            "description": "Primary start calendar date (no time)",
            "nullable": true
          },
          "project_end_date": {
            "type": "string",
            "format": "date",
            "description": "Primary end calendar date (no time)",
            "nullable": true
          },
          "project_time_start": {
            "type": "string",
            "description": "Start time of day (e.g. \"10:00 AM\")",
            "nullable": true
          },
          "project_time_end": {
            "type": "string",
            "description": "End time of day (e.g. \"6:00 PM\")",
            "nullable": true
          },
          "project_timezone": {
            "type": "string",
            "description": "READ-ONLY display label of the dates' zone (e.g. \"PDT\"); write `project_timezone_iana`",
            "nullable": true
          },
          "project_timezone_iana": {
            "type": "string",
            "description": "IANA timezone for the dates (e.g. \"America/Los_Angeles\")",
            "nullable": true
          },
          "project_location": {
            "type": "string",
            "description": "Primary location/venue",
            "nullable": true
          },
          "project_details": {
            "type": "string",
            "description": "Free-text project details",
            "nullable": true
          },
          "date_label": {
            "type": "string",
            "description": "Display label of the primary date (shown as the calendar entry title)",
            "nullable": true
          },
          "location_label": {
            "type": "string",
            "description": "Display label of the primary location",
            "nullable": true
          },
          "calendar_visible": {
            "type": "boolean",
            "description": "Whether the project shows as an entry on the member's calendar"
          },
          "space_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Ids of the company spaces linked to this project (BSON ObjectId hex)"
          },
          "last_activity_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last activity on the project (ISO8601)",
            "nullable": true
          },
          "guest_count": {
            "type": "integer",
            "format": "int32",
            "description": "Expected number of guests",
            "nullable": true
          },
          "budget": {
            "type": "integer",
            "format": "int32",
            "description": "Expected budget as the member entered it — a bare number in the company's currency, no minor units",
            "nullable": true
          },
          "lead_source_id": {
            "type": "string",
            "description": "Id of the company lead source this project is attributed to (BSON ObjectId hex); null when never set",
            "nullable": true
          },
          "lead_source_label": {
            "type": "string",
            "description": "Display label of that lead source (e.g. \"Referral\"), denormalized at write time",
            "nullable": true
          },
          "lead_source_open_text": {
            "type": "string",
            "description": "Free text the member entered for an \"other\" lead source; null otherwise",
            "nullable": true
          },
          "hide_conflict_action": {
            "type": "boolean",
            "description": "Whether the member dismissed the date-conflict banner for this project"
          },
          "editable": {
            "type": "boolean",
            "description": "PER-VIEWER. Whether the CALLER may edit this project: its creator, a company moderator or admin, or a team member who is on one of its workspaces. false for a team member who can read the company's projects but is not on this one."
          },
          "availability_type": {
            "type": "string",
            "description": "Availability kind (lowercase snake_case enum, e.g. busy, free)",
            "nullable": true
          },
          "source": {
            "type": "string",
            "description": "How the project was created (lowercase snake_case enum, e.g. manual)",
            "nullable": true
          },
          "client_portal_visible": {
            "type": "boolean",
            "description": "Whether the client portal link is surfaced to the client in this project's emails"
          },
          "project_type_id": {
            "type": "string",
            "description": "Id of the company ProjectType this project is classified as (BSON ObjectId hex)",
            "nullable": true
          },
          "company_id": {
            "type": "string",
            "description": "Owning (creator) company id (BSON ObjectId hex)",
            "nullable": true
          },
          "creator_id": {
            "type": "string",
            "description": "Id of the user who created the project (BSON ObjectId hex)",
            "nullable": true
          },
          "payroll_employee_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Payroll employee ids assigned to this project (opaque payroll strings)"
          },
          "dates": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_ProjectDate"
            },
            "description": "Additional project dates (embedded)"
          },
          "workspaces": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_Workspace_Projection"
              }
            ],
            "description": "The project's workspaces, OLDEST FIRST — `data[0]` is the workspace created with the project, so `POST /projects?include=workspaces` returns the id needed to add a member to the new project. Each workspace carries the caller's own `pipeline_stage`. null unless ?include=workspaces; `{ data: [], total_items: 0 }` when the project has none.",
            "nullable": true
          },
          "custom_fields": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_CustomFieldValue_Projection"
              }
            ],
            "description": "The project's custom field values, in the member's own field order — one row per LIVE field, with `value` null when unset. null unless ?include=custom_fields; `{ data: [], total_items: 0 }` when the company defines none.",
            "nullable": true
          },
          "cover_image": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Api_V3_Entities_ProjectCoverImage"
              }
            ],
            "description": "The project's cover image. null unless ?include=cover_image, and also null when the project has none.",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "Creation time (ISO8601)"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Last update time (ISO8601)"
          }
        },
        "required": [
          "id",
          "name",
          "project_date",
          "project_end_date",
          "project_time_start",
          "project_time_end",
          "project_timezone",
          "project_timezone_iana",
          "project_location",
          "project_details",
          "date_label",
          "location_label",
          "calendar_visible",
          "space_ids",
          "last_activity_at",
          "guest_count",
          "budget",
          "lead_source_id",
          "lead_source_label",
          "lead_source_open_text",
          "hide_conflict_action",
          "editable",
          "availability_type",
          "source",
          "client_portal_visible",
          "project_type_id",
          "company_id",
          "creator_id",
          "payroll_employee_ids",
          "dates",
          "workspaces",
          "custom_fields",
          "cover_image",
          "created_at",
          "updated_at"
        ],
        "description": "Api_V3_Entities_Project model"
      },
      "Api_V3_Entities_ProjectDate": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Project date id (BSON ObjectId hex)"
          },
          "date_label": {
            "type": "string",
            "description": "Label for this date (e.g. \"Ceremony\")",
            "nullable": true
          },
          "project_date": {
            "type": "string",
            "format": "date",
            "description": "Start calendar date (no time)",
            "nullable": true
          },
          "project_end_date": {
            "type": "string",
            "format": "date",
            "description": "End calendar date (no time)",
            "nullable": true
          },
          "project_time_start": {
            "type": "string",
            "description": "Start time of day (e.g. \"10:00 AM\")",
            "nullable": true
          },
          "project_time_end": {
            "type": "string",
            "description": "End time of day (e.g. \"6:00 PM\")",
            "nullable": true
          },
          "location": {
            "type": "string",
            "description": "Location for this date",
            "nullable": true
          },
          "location_label": {
            "type": "string",
            "description": "Label for the location",
            "nullable": true
          },
          "availability_type": {
            "type": "string",
            "description": "Availability kind for this date (lowercase snake_case enum)",
            "nullable": true
          }
        },
        "required": [
          "id",
          "date_label",
          "project_date",
          "project_end_date",
          "project_time_start",
          "project_time_end",
          "location",
          "location_label",
          "availability_type"
        ],
        "description": "Api_V3_Entities_ProjectDate model"
      },
      "Api_V3_Entities_Workspace_Projection": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_Workspace"
            },
            "description": "The projected rows, capped by the caller's max_*"
          },
          "total_items": {
            "type": "integer",
            "format": "int32",
            "description": "True total for this parent. total_items > data.length means the cap was hit"
          }
        },
        "required": [
          "data",
          "total_items"
        ]
      },
      "Api_V3_Entities_ProjectCoverImage": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "objectid",
            "description": "Image id"
          },
          "url": {
            "type": "string",
            "description": "Served image URL (a Cloudinary secure URL when the image was uploaded through Cloudinary)",
            "nullable": true
          },
          "original_url": {
            "type": "string",
            "description": "URL of the original the image was taken from",
            "nullable": true
          },
          "cloudinary_public_id": {
            "type": "string",
            "description": "Cloudinary public id, so a client may derive its own transformations; null for non-Cloudinary images",
            "nullable": true
          },
          "width": {
            "type": "integer",
            "format": "int32",
            "description": "Source width in pixels",
            "nullable": true
          },
          "height": {
            "type": "integer",
            "format": "int32",
            "description": "Source height in pixels",
            "nullable": true
          },
          "position_x": {
            "type": "integer",
            "format": "int32",
            "description": "Crop rectangle: left offset in pixels",
            "nullable": true
          },
          "position_y": {
            "type": "integer",
            "format": "int32",
            "description": "Crop rectangle: top offset in pixels",
            "nullable": true
          },
          "position_w": {
            "type": "integer",
            "format": "int32",
            "description": "Crop rectangle: width in pixels",
            "nullable": true
          },
          "position_h": {
            "type": "integer",
            "format": "int32",
            "description": "Crop rectangle: height in pixels",
            "nullable": true
          }
        },
        "required": [
          "id",
          "url",
          "original_url",
          "cloudinary_public_id",
          "width",
          "height",
          "position_x",
          "position_y",
          "position_w",
          "position_h"
        ]
      },
      "Api_V3_Entities_ProjectPayrollEmployeeCount": {
        "type": "object",
        "properties": {
          "employee_id": {
            "type": "string",
            "description": "Payroll employee id (opaque payroll string)"
          },
          "project_count": {
            "type": "integer",
            "format": "int32",
            "description": "Number of the company's projects this employee is assigned to"
          }
        },
        "required": [
          "employee_id",
          "project_count"
        ],
        "description": "Api_V3_Entities_ProjectPayrollEmployeeCount model"
      },
      "createProject": {
        "type": "object",
        "properties": {
          "include": {
            "type": "array",
            "description": "Comma-separated relations to populate. Allowed: workspaces, custom_fields, cover_image. A relation not requested is null. Nested paths (a.b) are not supported.",
            "items": {
              "type": "string",
              "enum": [
                "workspaces",
                "custom_fields",
                "cover_image"
              ]
            }
          },
          "max_workspaces": {
            "type": "integer",
            "format": "int32",
            "description": "Max workspaces per row (1..25, default 25). Ordered by created_at asc. Requires include=workspaces.",
            "minimum": 1,
            "maximum": 25
          },
          "max_custom_fields": {
            "type": "integer",
            "format": "int32",
            "description": "Max custom_fields per row (1..50, default 50). Ordered by order asc. Requires include=custom_fields.",
            "minimum": 1,
            "maximum": 50
          },
          "name": {
            "type": "string",
            "description": "Project display name (auto-generated if omitted)"
          },
          "project_date": {
            "type": "string",
            "format": "date",
            "description": "Primary start calendar date"
          },
          "project_end_date": {
            "type": "string",
            "format": "date",
            "description": "Primary end calendar date"
          },
          "project_time_start": {
            "type": "string",
            "description": "Start time of day (e.g. \"10:00 AM\")"
          },
          "project_time_end": {
            "type": "string",
            "description": "End time of day"
          },
          "project_timezone_iana": {
            "type": "string",
            "description": "IANA timezone of the dates (e.g. \"America/New_York\"); defaults to the company's"
          },
          "project_location": {
            "type": "string",
            "description": "Primary location/venue"
          },
          "project_details": {
            "type": "string",
            "description": "Free-text project details"
          },
          "guest_count": {
            "type": "integer",
            "format": "int32",
            "description": "Expected number of guests"
          },
          "budget": {
            "type": "integer",
            "format": "int32",
            "description": "Expected budget, a bare number in the company's currency"
          },
          "availability_type": {
            "type": "string",
            "description": "Availability kind (lowercase snake_case enum)",
            "enum": [
              "busy",
              "free"
            ]
          },
          "project_type_id": {
            "type": "string",
            "description": "Company ProjectType id to classify the project"
          },
          "lead_source_id": {
            "type": "string",
            "description": "Id of one of the company's lead sources to attribute the project to"
          },
          "lead_source_open_text": {
            "type": "string",
            "description": "Free text for an \"other\" lead source"
          },
          "stage_id": {
            "type": "string",
            "description": "Pipeline stage of the new workspace; takes precedence over `group`"
          },
          "group": {
            "type": "string",
            "description": "Pipeline group whose first stage the new workspace starts in",
            "enum": [
              "opportunities",
              "projects"
            ]
          },
          "source": {
            "type": "string",
            "description": "How the project was created (lowercase snake_case enum)",
            "enum": [
              "manual",
              "google",
              "widget",
              "company_team",
              "vendor_referral",
              "assign_user",
              "event_member",
              "questionnaire_automation",
              "brochure",
              "self_onboarding",
              "group_widget",
              "group_member",
              "aisle_society",
              "loverly",
              "main_street_weddings",
              "manual_group_lead",
              "vendor_mobile",
              "malkut_venue_onboarding",
              "network_project",
              "wedding_spot",
              "network_invite",
              "pvl_inquiry",
              "first_invoice",
              "rts_survey",
              "community_lp",
              "workflow_automation",
              "community_widget",
              "zapier",
              "client_bot",
              "manual_ios_app",
              "facebook_lead_ads",
              "contact_csv",
              "first_proposal",
              "manual_android_app",
              "direct_link",
              "scheduler",
              "hb_chrome_extension",
              "agraba",
              "promotion",
              "gift_card",
              "preview",
              "onboarding",
              "flow_automation",
              "send_test_template",
              "send_test_setup_guide",
              "shared_template",
              "public_flow",
              "awareness_draft",
              "onboarding_ios_app",
              "onboarding_android_app",
              "lifecycle_marketing",
              "setup_guide",
              "smart_file_wizard",
              "schedule_intent_onboarding",
              "lead_capture_intent_onboarding",
              "public_template_sharing",
              "dispute_invoice_flow",
              "import_pdf",
              "ai_templates",
              "automations",
              "projects_file",
              "ai_lead_suggestion",
              "tkww",
              "calendly",
              "google_calendar",
              "referral_request_suggestion",
              "chat_onboarding",
              "unassigned_to_project",
              "post_project_tip",
              "preset_template",
              "mcp",
              "entities",
              "import_gallery",
              "inbound_sms",
              "honeybook_ai",
              "agent_booking",
              "onboarding_proposal",
              "ai_gmail_integration",
              "gallery_store"
            ]
          },
          "custom_fields": {
            "type": "array",
            "description": "Values for the company's custom fields of this record's kind. MERGE, not replace: only the listed fields are written, the rest keep their value. Each entry is validated like `PATCH .../custom_fields/:field_id` before anything is written: an unknown, foreign, archived or wrong-kind `field_id` is a 404; an invalid `value`, a repeated `field_id` or more than 50 entries is a 400, and nothing is written.",
            "items": {
              "type": "object",
              "properties": {
                "field_id": {
                  "type": "string",
                  "description": "Custom field id (the `id` of a GET /custom_fields row)"
                },
                "value": {
                  "type": "string",
                  "description": "The new value as a String: a number as its digits, a date as ISO8601, a single_select as the option's id, a multi_select as comma-separated option ids. `null` clears the value."
                }
              },
              "required": [
                "field_id",
                "value"
              ]
            }
          }
        },
        "description": "Create a project"
      },
      "updateProject": {
        "type": "object",
        "properties": {
          "include": {
            "type": "array",
            "description": "Comma-separated relations to populate. Allowed: workspaces, custom_fields, cover_image. A relation not requested is null. Nested paths (a.b) are not supported.",
            "items": {
              "type": "string",
              "enum": [
                "workspaces",
                "custom_fields",
                "cover_image"
              ]
            }
          },
          "max_workspaces": {
            "type": "integer",
            "format": "int32",
            "description": "Max workspaces per row (1..25, default 25). Ordered by created_at asc. Requires include=workspaces.",
            "minimum": 1,
            "maximum": 25
          },
          "max_custom_fields": {
            "type": "integer",
            "format": "int32",
            "description": "Max custom_fields per row (1..50, default 50). Ordered by order asc. Requires include=custom_fields.",
            "minimum": 1,
            "maximum": 50
          },
          "name": {
            "type": "string"
          },
          "project_date": {
            "type": "string",
            "format": "date"
          },
          "project_end_date": {
            "type": "string",
            "format": "date"
          },
          "project_time_start": {
            "type": "string"
          },
          "project_time_end": {
            "type": "string"
          },
          "project_timezone_iana": {
            "type": "string",
            "description": "IANA timezone of the dates (e.g. \"America/New_York\")"
          },
          "project_location": {
            "type": "string"
          },
          "date_label": {
            "type": "string",
            "description": "Display label of the primary date; blank falls back to the project name"
          },
          "location_label": {
            "type": "string",
            "description": "Display label of the primary location"
          },
          "calendar_visible": {
            "type": "boolean",
            "description": "Whether the project shows as an entry on the member's calendar"
          },
          "project_details": {
            "type": "string"
          },
          "guest_count": {
            "type": "integer",
            "format": "int32"
          },
          "budget": {
            "type": "integer",
            "format": "int32",
            "description": "Expected budget, a bare number in the company's currency"
          },
          "availability_type": {
            "type": "string",
            "enum": [
              "busy",
              "free"
            ]
          },
          "project_type_id": {
            "type": "string"
          },
          "lead_source_id": {
            "type": "string",
            "description": "Id of one of the company's lead sources to attribute the project to"
          },
          "lead_source_open_text": {
            "type": "string",
            "description": "Free text for an \"other\" lead source"
          },
          "client_portal_visible": {
            "type": "boolean",
            "description": "Surface/hide the client portal link in this project's client emails (plain flag, no side effect)"
          },
          "hide_conflict_action": {
            "type": "boolean",
            "description": "Dismiss (true) or restore (false) the date-conflict banner for this project"
          },
          "custom_fields": {
            "type": "array",
            "description": "Values for the company's custom fields of this record's kind. MERGE, not replace: only the listed fields are written, the rest keep their value. Each entry is validated like `PATCH .../custom_fields/:field_id` before anything is written: an unknown, foreign, archived or wrong-kind `field_id` is a 404; an invalid `value`, a repeated `field_id` or more than 50 entries is a 400, and nothing is written.",
            "items": {
              "type": "object",
              "properties": {
                "field_id": {
                  "type": "string",
                  "description": "Custom field id (the `id` of a GET /custom_fields row)"
                },
                "value": {
                  "type": "string",
                  "description": "The new value as a String: a number as its digits, a date as ISO8601, a single_select as the option's id, a multi_select as comma-separated option ids. `null` clears the value."
                }
              },
              "required": [
                "field_id",
                "value"
              ]
            }
          }
        },
        "description": "Update a project (partial; data fields only)"
      },
      "updateProjectDate": {
        "type": "object",
        "properties": {
          "date_label": {
            "type": "string"
          },
          "project_date": {
            "type": "string",
            "format": "date"
          },
          "project_end_date": {
            "type": "string",
            "format": "date"
          },
          "project_time_start": {
            "type": "string"
          },
          "project_time_end": {
            "type": "string"
          },
          "location": {
            "type": "string"
          },
          "location_label": {
            "type": "string"
          },
          "availability_type": {
            "type": "string",
            "enum": [
              "busy",
              "free"
            ]
          }
        },
        "description": "Update a project date (partial)"
      },
      "Api_V3_Entities_ProjectPayrollEmployees": {
        "type": "object",
        "properties": {
          "employee_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Payroll employee ids assigned to this project (opaque payroll strings)"
          }
        },
        "required": [
          "employee_ids"
        ],
        "description": "Api_V3_Entities_ProjectPayrollEmployees model"
      },
      "Api_V3_Entities_ProjectConflicts": {
        "type": "object",
        "properties": {
          "has_conflict": {
            "type": "boolean",
            "description": "Whether any conflicting project exists"
          },
          "lead_conflicting_project_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Ids of conflicting lead (unbooked) projects (BSON ObjectId hex)"
          },
          "booked_conflicting_project_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Ids of conflicting booked projects (BSON ObjectId hex)"
          },
          "lead_conflicting_projects": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_ProjectConflictRef"
            },
            "description": "The conflicting lead (unbooked) projects, id and name, in the same order as lead_conflicting_project_ids"
          },
          "booked_conflicting_projects": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Api_V3_Entities_ProjectConflictRef"
            },
            "description": "The conflicting booked projects, id and name, in the same order as booked_conflicting_project_ids"
          }
        },
        "required": [
          "has_conflict",
          "lead_conflicting_project_ids",
          "booked_conflicting_project_ids",
          "lead_conflicting_projects",
          "booked_conflicting_projects"
        ],
        "description": "Api_V3_Entities_ProjectConflicts model"
      },
      "Api_V3_Entities_ProjectConflictRef": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Conflicting project id (BSON ObjectId hex)"
          },
          "name": {
            "type": "string",
            "description": "Conflicting project display name",
            "nullable": true
          }
        },
        "required": [
          "id",
          "name"
        ]
      },
      "createProjectWorkspace": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "description": "Workspace kind (lowercase snake_case enum) — matches the Workspaces domain vocabulary",
            "enum": [
              "general",
              "team",
              "design",
              "all_vendors",
              "timeline"
            ],
            "default": "general"
          }
        },
        "description": "Create a workspace on a project"
      },
      "updateProjectCustomField": {
        "type": "object",
        "properties": {
          "value": {
            "type": "string",
            "description": "The new value, as a String — see the operation description"
          }
        },
        "required": [
          "value"
        ],
        "description": "Set a project's value for one custom field"
      },
      "Api_V3_Entities_CustomFieldValue_Shared": {
        "type": "object",
        "properties": {
          "field_id": {
            "type": "string",
            "description": "Id of the custom field definition this value belongs to (BSON ObjectId hex) — the `id` of a GET /custom_fields row, and the `:field_id` to PATCH"
          },
          "name": {
            "type": "string",
            "description": "Display name of the custom field, as the member defined it",
            "nullable": true
          },
          "type": {
            "type": "string",
            "enum": [
              "text",
              "long_text",
              "date",
              "number",
              "link",
              "single_select",
              "multi_select"
            ],
            "description": "The field's value kind — the discriminator. One of: text, long_text, date, number, link, single_select, multi_select"
          },
          "archived": {
            "type": "boolean",
            "description": "Whether the member deleted this field. Only an archived field that still holds a value on this record is returned"
          }
        },
        "required": [
          "field_id",
          "name",
          "type",
          "archived"
        ],
        "description": "Fields every CustomFieldValue carries, whatever kind it is"
      }
    }
  },
  "x-tagGroups": [
    {
      "name": "",
      "tags": [
        "Request Access"
      ]
    },
    {
      "name": "Guides",
      "tags": [
        "Authentication",
        "Errors",
        "Idempotency",
        "Pagination",
        "Filtering & Sorting",
        "Relation Includes",
        "Async Operations"
      ]
    },
    {
      "name": "API Reference",
      "tags": [
        "Contacts",
        "CustomFields",
        "Inquiries",
        "Pipeline",
        "Workspaces",
        "LeadSources",
        "Projects"
      ]
    }
  ],
  "security": [
    {
      "oauth2": []
    }
  ]
}
