{
  "openapi": "3.0.0",
  "paths": {
    "/api/v1/me": {
      "get": {
        "operationId": "getMe",
        "parameters": [],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MeResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "Test authentication — identifies the workspace behind the key",
        "tags": [
          "Public API v1"
        ]
      }
    },
    "/api/v1/funnels": {
      "get": {
        "operationId": "listFunnels",
        "parameters": [
          {
            "name": "search",
            "required": false,
            "in": "query",
            "description": "Filter by name, case-insensitive.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "required": false,
            "in": "query",
            "description": "Opaque cursor from the previous page’s `nextCursor`. Send it back verbatim; do not build one.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "description": "Rows per page (max 200). A full page never means \"that is all\" — read `nextCursor`.",
            "schema": {
              "maximum": 200,
              "default": 200,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FunnelListResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "List funnels of the workspace (for platform dropdowns)",
        "tags": [
          "Public API v1"
        ]
      },
      "post": {
        "operationId": "createFunnel",
        "parameters": [
          {
            "name": "idempotency-key",
            "required": true,
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateFunnelPublicDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FunnelDetailDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "Workspace archived past its 7-day grace window (`code: WORKSPACE_ARCHIVED`). The key is still valid — reads keep working and this resumes on restore. Do not re-issue a key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Template not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "Create a custom, optionally cloned from a template. Always a DRAFT — nothing is public until publish.",
        "tags": [
          "Public API v1"
        ]
      }
    },
    "/api/v1/funnels/{id}/fields": {
      "get": {
        "operationId": "listFunnelFields",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FunnelFieldsResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Funnel not found in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "List a funnel’s mappable columns — drives the dynamic field mapping of platform apps",
        "tags": [
          "Public API v1"
        ]
      }
    },
    "/api/v1/funnels/{id}": {
      "delete": {
        "operationId": "deleteFunnel",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Trashed."
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "Workspace archived past its 7-day grace window (`code: WORKSPACE_ARCHIVED`). The key is still valid — reads keep working and this resumes on restore. Do not re-issue a key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Funnel not found in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "Move a custom to the trash. Soft — it stays recoverable from the dashboard, which is why an agent may be trusted with it at all.",
        "tags": [
          "Public API v1"
        ]
      },
      "get": {
        "operationId": "getFunnel",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FunnelDetailDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Funnel not found in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "One custom: its three version pointers, whether the draft has moved, and where a person opens it.",
        "tags": [
          "Public API v1"
        ]
      }
    },
    "/api/v1/templates": {
      "get": {
        "operationId": "listTemplates",
        "parameters": [],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TemplateListResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "Templates you can clone. Cloning one is the cheapest route to a publishable custom — it brings questions, result page and scenes with it.",
        "tags": [
          "Public API v1"
        ]
      }
    },
    "/api/v1/funnels/{id}/readiness": {
      "get": {
        "operationId": "getFunnelReadiness",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReadinessResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Funnel not found in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "What still stands between this draft and a publish — WITHOUT publishing. Each item says which room fixes it and whether you can fix it yourself.",
        "tags": [
          "Public API v1"
        ]
      }
    },
    "/api/v1/funnels/{id}/questions": {
      "get": {
        "operationId": "getFunnelQuestions",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The draft question set."
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Funnel not found in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "The draft’s questions. Read before you write — the write replaces the set.",
        "tags": [
          "Public API v1"
        ]
      },
      "patch": {
        "operationId": "setFunnelQuestions",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkSetQuestionDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The question set as stored."
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "Workspace archived past its 7-day grace window (`code: WORKSPACE_ARCHIVED`). The key is still valid — reads keep working and this resumes on restore. Do not re-issue a key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Funnel not found in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "REPLACE the question set. The contact step and the end screen are questions too (CONTACT / PROCESS) — exactly one of each. People-only columns (askInQuiz: false) must be repeated or they are deleted.",
        "tags": [
          "Public API v1"
        ]
      }
    },
    "/api/v1/funnels/{id}/scores": {
      "get": {
        "operationId": "getFunnelScores",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The draft score set."
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Funnel not found in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "The draft’s score definitions.",
        "tags": [
          "Public API v1"
        ]
      },
      "patch": {
        "operationId": "setFunnelScores",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkSetScoreDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The score set as stored."
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "Workspace archived past its 7-day grace window (`code: WORKSPACE_ARCHIVED`). The key is still valid — reads keep working and this resumes on restore. Do not re-issue a key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Funnel not found in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "REPLACE the score set. Scores run at submission, so a broken one fails leads long before any video exists — they gate publishing for that reason.",
        "tags": [
          "Public API v1"
        ]
      }
    },
    "/api/v1/funnels/{id}/segments": {
      "get": {
        "operationId": "getFunnelSegments",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The draft scene set."
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Funnel not found in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "The scenes: which clips exist and when each plays.",
        "tags": [
          "Public API v1"
        ]
      },
      "patch": {
        "operationId": "setFunnelSegments",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublicBulkSetSegmentDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The scene set as stored."
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "Workspace archived past its 7-day grace window (`code: WORKSPACE_ARCHIVED`). The key is still valid — reads keep working and this resumes on restore. Do not re-issue a key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Funnel not found in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "REPLACE the scenes. You author the structure, never the footage — filming is the one step no API replaces, and this endpoint carries no field for it. A scene references its background page by SLUG, not id: page ids are regenerated on every save.",
        "tags": [
          "Public API v1"
        ]
      }
    },
    "/api/v1/funnels/{id}/clip-scripts": {
      "post": {
        "operationId": "generateClipScripts",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "idempotency-key",
            "required": true,
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateScriptsDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Scripts, per clip slot."
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "Workspace archived past its 7-day grace window (`code: WORKSPACE_ARCHIVED`). The key is still valid — reads keep working and this resumes on restore. Do not re-issue a key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Funnel not found in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "Write the words a human will read on camera. This is what makes the hand-off usable — the person is handed scripts, not empty slots. Costs an AI call per clip; not something to loop on.",
        "tags": [
          "Public API v1"
        ]
      }
    },
    "/api/v1/funnels/{id}/pages/{pageSlug}/html-blocks": {
      "post": {
        "operationId": "createHtmlBlocks",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "pageSlug",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateHtmlBlocksDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HtmlBlocksCreatedDto"
                }
              }
            }
          },
          "400": {
            "description": "A block had no code, or the page has no canvas to place it in — a page that has never been opened in the editor has none.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Funnel not found in this workspace, or no page with that slug on its draft.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "Add Custom HTML blocks to a result page, and get back a link to see how it renders. Placement only — send the HTML you wrote; nothing is generated for you.",
        "tags": [
          "Public API v1"
        ]
      }
    },
    "/api/v1/funnels/{id}/result-page-previews": {
      "post": {
        "operationId": "createResultPagePreview",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateResultPagePreviewDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResultPagePreviewDto"
                }
              }
            }
          },
          "400": {
            "description": "None of the answers matched a question, or this custom cannot produce a result page for them.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Funnel not found in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "See a draft result page for one set of answers, without publishing and without spending a submission. Returns a link that expires. Use it to check what you just wrote instead of opening the builder.",
        "tags": [
          "Public API v1"
        ]
      }
    },
    "/api/v1/funnels/{id}/publish": {
      "post": {
        "operationId": "publishFunnel",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "idempotency-key",
            "required": true,
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FunnelDetailDto"
                }
              }
            }
          },
          "400": {
            "description": "Not publishable. The body carries `details: [{ code, message }]` — every blocker at once, not the first. `GET /funnels/:id/readiness` returns the same list with a room and a link per item, and writes nothing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "Workspace archived past its 7-day grace window (`code: WORKSPACE_ARCHIVED`). The key is still valid — reads keep working and this resumes on restore. Do not re-issue a key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Funnel not found in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "Take the draft live. Refuses while anything is missing — call readiness first; publishing is not how you find out what is wrong.",
        "tags": [
          "Public API v1"
        ]
      }
    },
    "/api/v1/hooks": {
      "post": {
        "operationId": "createHook",
        "parameters": [
          {
            "name": "idempotency-key",
            "required": true,
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateHookDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HookDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "Workspace archived past its 7-day grace window (`code: WORKSPACE_ARCHIVED`). The key is still valid — reads keep working and this resumes on restore. Do not re-issue a key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "Subscribe a REST hook (instant trigger) — events will be POSTed to the given URL",
        "tags": [
          "Public API v1"
        ]
      },
      "get": {
        "operationId": "listHooks",
        "parameters": [],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HookListResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "List API-created hooks of the workspace",
        "tags": [
          "Public API v1"
        ]
      }
    },
    "/api/v1/hooks/{id}": {
      "delete": {
        "operationId": "deleteHook",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Hook removed."
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "Workspace archived past its 7-day grace window (`code: WORKSPACE_ARCHIVED`). The key is still valid — reads keep working and this resumes on restore. Do not re-issue a key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Hook not found (or not API-created).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "Unsubscribe a REST hook (dashboard-created webhooks are not reachable here)",
        "tags": [
          "Public API v1"
        ]
      },
      "patch": {
        "operationId": "updateHook",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateHookDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HookDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "Workspace archived past its 7-day grace window (`code: WORKSPACE_ARCHIVED`). The key is still valid — reads keep working and this resumes on restore. Do not re-issue a key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Hook not found, not API-created, or the target funnel is not in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "Change a subscription in place — URL, events, funnel scope, active state. Avoids the delete-and-recreate gap, during which events are lost.",
        "tags": [
          "Public API v1"
        ]
      }
    },
    "/api/v1/sources": {
      "post": {
        "operationId": "createSource",
        "parameters": [
          {
            "name": "idempotency-key",
            "required": true,
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateSourceDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SourceSecretResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "Workspace archived past its 7-day grace window (`code: WORKSPACE_ARCHIVED`). The key is still valid — reads keep working and this resumes on restore. Do not re-issue a key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Funnel not found in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "Create a per-funnel inbound endpoint. Returns the paste-ready ingest URL — that URL is the deliverable.",
        "tags": [
          "Public API v1"
        ]
      },
      "get": {
        "operationId": "listSources",
        "parameters": [
          {
            "name": "funnelId",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SourceListResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "List a funnel’s inbound sources (never the secret).",
        "tags": [
          "Public API v1"
        ]
      }
    },
    "/api/v1/sources/{id}": {
      "get": {
        "operationId": "getSource",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SourceDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Source not found in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "One inbound source (never the secret).",
        "tags": [
          "Public API v1"
        ]
      },
      "patch": {
        "operationId": "updateSource",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateSourceDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SourceDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "Workspace archived past its 7-day grace window (`code: WORKSPACE_ARCHIVED`). The key is still valid — reads keep working and this resumes on restore. Do not re-issue a key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Source not found in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "Amend name, field mappings, active state or autoSubmit. The funnel is fixed at creation.",
        "tags": [
          "Public API v1"
        ]
      },
      "delete": {
        "operationId": "deleteSource",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Source removed."
          },
          "400": {
            "description": "The source has already received data and cannot be deleted — the rows it produced would lose where they came from. Set `isActive: false` instead: it stops accepting payloads and keeps the trail.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "Workspace archived past its 7-day grace window (`code: WORKSPACE_ARCHIVED`). The key is still valid — reads keep working and this resumes on restore. Do not re-issue a key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Source not found in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "Delete an inbound source. Rows it already produced are kept.",
        "tags": [
          "Public API v1"
        ]
      }
    },
    "/api/v1/sources/{id}/secret": {
      "get": {
        "operationId": "revealSourceSecret",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SourceSecretResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Source not found in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "Rebuild the ingest URL for an existing source.",
        "tags": [
          "Public API v1"
        ]
      }
    },
    "/api/v1/sources/{id}/rotate-secret": {
      "post": {
        "operationId": "rotateSourceSecret",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SourceSecretResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "Workspace archived past its 7-day grace window (`code: WORKSPACE_ARCHIVED`). The key is still valid — reads keep working and this resumes on restore. Do not re-issue a key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Source not found in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "Mint a new secret. The previous ingest URL stops working immediately — re-paste before rotating.",
        "tags": [
          "Public API v1"
        ]
      }
    },
    "/api/v1/sources/{id}/import": {
      "post": {
        "operationId": "importSourceCsv",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImportCsvDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CsvImportResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "The source is not `type: \"csv\"` (a webhook source refuses file imports), the CSV has no header row, or it exceeds 400 KB. Past ~512 KB the body parser refuses it first with a bare **413** carrying no explanation — split the file, or import it from the dashboard, which takes 10 MB.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "Workspace archived past its 7-day grace window (`code: WORKSPACE_ARCHIVED`). The key is still valid — reads keep working and this resumes on restore. Do not re-issue a key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Source not found in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "Import CSV text as PENDING rows. They are not leads until submitted — no video renders and nothing is billed.",
        "tags": [
          "Public API v1"
        ]
      }
    },
    "/api/v1/leads": {
      "get": {
        "operationId": "listLeads",
        "parameters": [
          {
            "name": "funnelId",
            "required": false,
            "in": "query",
            "description": "Only leads of this funnel.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "required": false,
            "in": "query",
            "description": "Opaque cursor from the previous page’s `nextCursor`. Send it back verbatim; do not build one.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "description": "Rows per page (max 100). A full page never means \"that is all\" — read `nextCursor`.",
            "schema": {
              "maximum": 100,
              "default": 25,
              "type": "number"
            }
          },
          {
            "name": "createdAfter",
            "required": false,
            "in": "query",
            "description": "Leads created strictly after this instant.",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "createdBefore",
            "required": false,
            "in": "query",
            "description": "Leads created strictly before this instant.",
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          },
          {
            "name": "productPurchased",
            "required": false,
            "in": "query",
            "description": "Filter on the conversion flag set by PATCH /leads/:id.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LeadListResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "List the workspace’s leads, newest first. Cursor-paginated — `nextCursor: null` is the only end signal.",
        "tags": [
          "Public API v1"
        ]
      },
      "post": {
        "operationId": "createLead",
        "parameters": [
          {
            "name": "idempotency-key",
            "required": true,
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateLeadDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateLeadResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "Workspace archived (`code: WORKSPACE_ARCHIVED`). Creating a lead is ENTRY, which stops IMMEDIATELY on archive — there is no grace window here, unlike the five management writes. The key is still valid: reads keep working and this resumes on restore. Do not re-issue a key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Funnel not found in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "409": {
            "description": "The funnel cannot accept a submission — no published version, or no questions on it. Also returned when an Idempotency-Key request is still in flight.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "Create a lead in a funnel (Action). Supports an Idempotency-Key header — a retried request never creates a duplicate.",
        "tags": [
          "Public API v1"
        ]
      }
    },
    "/api/v1/leads/sample": {
      "get": {
        "operationId": "listSampleLeads",
        "parameters": [
          {
            "name": "funnelId",
            "required": true,
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SampleLeadsResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "Recent leads shaped like the diagnostic.submitted payload (for platform trigger tests) — read-only",
        "tags": [
          "Public API v1"
        ]
      }
    },
    "/api/v1/leads/{id}": {
      "patch": {
        "operationId": "updateLead",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateLeadDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UpdateLeadResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "Workspace archived past its 7-day grace window (`code: WORKSPACE_ARCHIVED`). The key is still valid — reads keep working and this resumes on restore. Do not re-issue a key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Lead not found in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "Update a lead — mark purchased / add a note. false→true on productPurchased fires lead.purchased.",
        "tags": [
          "Public API v1"
        ]
      }
    },
    "/api/v1/tags": {
      "get": {
        "operationId": "listTags",
        "parameters": [],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TagListResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "List the workspace tags (for dropdowns)",
        "tags": [
          "Public API v1"
        ]
      }
    },
    "/api/v1/leads/{id}/tags": {
      "post": {
        "operationId": "addLeadTags",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LeadTagsDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LeadTagsResponseDto"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "Workspace archived past its 7-day grace window (`code: WORKSPACE_ARCHIVED`). The key is still valid — reads keep working and this resumes on restore. Do not re-issue a key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Lead not found in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "409": {
            "description": "Lead has no contact to tag.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "Add tags (by name, created if missing) to the lead's contact",
        "tags": [
          "Public API v1"
        ]
      },
      "delete": {
        "operationId": "removeLeadTags",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LeadTagsDto"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "Tags removed."
          },
          "400": {
            "description": "Invalid request body or parameters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, or revoked API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "403": {
            "description": "Workspace archived past its 7-day grace window (`code: WORKSPACE_ARCHIVED`). The key is still valid — reads keep working and this resumes on restore. Do not re-issue a key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "404": {
            "description": "Lead not found in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "429": {
            "description": "Two distinct limits share this status — read `code`. `RATE_LIMITED`: 600 requests/minute per key; a `Retry-After` header says when to retry. `DAILY_LEAD_LIMIT`: the workspace daily lead cap is spent; there is no `Retry-After` and the window only resets at midnight UTC — do not retry on a short backoff.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          },
          "500": {
            "description": "Something broke on our side, not in your request — do not rewrite the payload. Carries a `referenceId` to quote to support. Safe to retry, and safe to retry with the same `Idempotency-Key`: a request that failed here consumed neither the key nor a daily-lead slot.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorDto"
                }
              }
            }
          }
        },
        "security": [
          {
            "api-key": []
          }
        ],
        "summary": "Remove tags (by name) from the lead's contact",
        "tags": [
          "Public API v1"
        ]
      }
    }
  },
  "info": {
    "title": "Custom One Public API",
    "description": "Create and enrich leads, subscribe to lead-journey events, and read a funnel's columns. Authenticate every request with a workspace API key (`Authorization: Bearer co_live_…` or the `X-API-Key` header). The key prefix selects the host: `co_live_` → production, `co_test_` → development.",
    "version": "1.1.0",
    "contact": {},
    "x-spec-hash": "59d5ea8717ed1b65"
  },
  "tags": [],
  "servers": [
    {
      "url": "https://api.custom.one",
      "description": "Production"
    },
    {
      "url": "https://dev.api.custom.one",
      "description": "Development"
    }
  ],
  "components": {
    "securitySchemes": {
      "api-key": {
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "type": "http",
        "description": "Workspace API key. Also accepted as the `X-API-Key` header (same value, no \"Bearer\" prefix)."
      }
    },
    "schemas": {
      "ApiErrorDto": {
        "type": "object",
        "properties": {
          "statusCode": {
            "type": "number",
            "example": 400
          },
          "message": {
            "description": "Human-readable reasons. Always an array, even for a single message — the filter normalises it.",
            "example": [
              "Unknown field(s) for this funnel: q-deleted"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "error": {
            "type": "string",
            "example": "Bad Request"
          },
          "code": {
            "type": "string",
            "enum": [
              "RATE_LIMITED",
              "DAILY_LEAD_LIMIT",
              "WORKSPACE_ARCHIVED"
            ],
            "description": "Stable discriminator, present when the status alone is ambiguous. Branch on this, not on the message.",
            "example": "DAILY_LEAD_LIMIT"
          },
          "referenceId": {
            "type": "string",
            "description": "Correlation id minted for an UNEXPECTED error — quote it to support. Only ever appears on a 500.",
            "example": "7b1f6a2e-2c40-4c1e-9f5b-2a1d0c9e3f44"
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "example": "2026-08-27T09:41:12.004Z"
          },
          "path": {
            "type": "string",
            "description": "Request path that produced the error.",
            "example": "/api/v1/leads"
          }
        },
        "required": [
          "statusCode",
          "message",
          "error",
          "timestamp",
          "path"
        ]
      },
      "WorkspaceRefDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "69ca4e72a1e565654bd303f1"
          },
          "name": {
            "type": "string",
            "example": "AlexOrganization"
          }
        },
        "required": [
          "id",
          "name"
        ]
      },
      "ApiKeyRefDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "6a6071083eb294d9ec3d2c55"
          },
          "label": {
            "type": "string",
            "example": "Make production"
          },
          "keyPrefix": {
            "type": "string",
            "description": "First 12 chars of the key, for display",
            "example": "co_live_2f01"
          }
        },
        "required": [
          "id",
          "label",
          "keyPrefix"
        ]
      },
      "MeResponseDto": {
        "type": "object",
        "properties": {
          "workspace": {
            "$ref": "#/components/schemas/WorkspaceRefDto"
          },
          "key": {
            "$ref": "#/components/schemas/ApiKeyRefDto"
          }
        },
        "required": [
          "workspace",
          "key"
        ]
      },
      "FunnelListItemDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "6a7adc2a04b6d21bdd5af2a3"
          },
          "name": {
            "type": "string",
            "example": "Ton plan de reprise sportive"
          },
          "slug": {
            "type": "string",
            "example": "aZ3kP0qL9x"
          },
          "status": {
            "type": "string",
            "example": "published",
            "description": "draft | published"
          },
          "isActive": {
            "type": "boolean",
            "example": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "name",
          "slug",
          "status",
          "isActive",
          "createdAt"
        ]
      },
      "FunnelListResponseDto": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FunnelListItemDto"
            }
          },
          "nextCursor": {
            "type": "string",
            "nullable": true,
            "description": "Cursor for the next page, or null at the end. **The only end signal** — a short page does not mean there is no more. Before this existed the list was capped at 200 and said nothing, so a workspace with more customs silently lost the rest."
          }
        },
        "required": [
          "data",
          "nextCursor"
        ]
      },
      "FunnelFieldOptionDto": {
        "type": "object",
        "properties": {
          "label": {
            "type": "string",
            "example": "Sédentaire"
          },
          "value": {
            "type": "string",
            "example": "sedentaire"
          }
        },
        "required": [
          "label",
          "value"
        ]
      },
      "FunnelFieldDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Opaque identifier — send it back verbatim as a `replies` key.",
            "example": "q-a1b2c3"
          },
          "label": {
            "type": "string",
            "example": "Activity level"
          },
          "type": {
            "type": "string",
            "enum": [
              "text",
              "url",
              "number",
              "boolean",
              "date",
              "email",
              "phone",
              "select",
              "multiselect"
            ],
            "description": "Platform-neutral field type."
          },
          "required": {
            "type": "boolean"
          },
          "dataOnly": {
            "type": "boolean",
            "description": "True for a People-only column, never asked in the quiz."
          },
          "options": {
            "description": "Present on select/multiselect only.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FunnelFieldOptionDto"
            }
          }
        },
        "required": [
          "name",
          "label",
          "type",
          "required",
          "dataOnly"
        ]
      },
      "FunnelFieldsResponseDto": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FunnelFieldDto"
            }
          }
        },
        "required": [
          "data"
        ]
      },
      "CreateFunnelPublicDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Fitness readiness quiz",
            "minLength": 1,
            "maxLength": 100
          },
          "fromTemplateId": {
            "type": "string",
            "description": "Clone this template (or an existing custom of the workspace) instead of starting empty. By far the cheapest way to get something publishable: the clone brings its questions, result page and scenes with it, and they only need editing. `GET /templates` lists them."
          },
          "language": {
            "type": "string",
            "example": "en",
            "description": "⚠️ An ABSENT language means French, not English — the creator’s own language is used and the seed copy follows it. Set it explicitly unless you want that."
          }
        },
        "required": [
          "name"
        ]
      },
      "FunnelDetailDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string",
            "description": "Ten random characters, fixed at creation and never derived from the name."
          },
          "status": {
            "type": "string",
            "example": "draft",
            "description": "draft | active"
          },
          "isActive": {
            "type": "boolean"
          },
          "language": {
            "type": "object",
            "nullable": true,
            "description": "Absent means French — set it explicitly on create."
          },
          "draftVersionId": {
            "type": "object",
            "nullable": true,
            "description": "Where every authoring write lands. Nothing here is public until a publish."
          },
          "activeVersionId": {
            "type": "object",
            "nullable": true,
            "description": "What visitors currently see. Null until first publish."
          },
          "intakeVersionId": {
            "type": "object",
            "nullable": true,
            "description": "Version the public quiz and external ingestion read."
          },
          "hasUnpublishedChanges": {
            "type": "boolean",
            "description": "True when the draft has moved past what is live."
          },
          "editorUrl": {
            "type": "string",
            "format": "uri",
            "description": "The custom in the dashboard — hand this to a person."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "name",
          "slug",
          "status",
          "isActive",
          "language",
          "draftVersionId",
          "activeVersionId",
          "intakeVersionId",
          "hasUnpublishedChanges",
          "editorUrl",
          "createdAt"
        ]
      },
      "TemplateDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "example": "Fitness readiness"
          },
          "language": {
            "type": "object",
            "nullable": true
          }
        },
        "required": [
          "id",
          "name",
          "language"
        ]
      },
      "TemplateListResponseDto": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TemplateDto"
            }
          }
        },
        "required": [
          "data"
        ]
      },
      "HandoffStepDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "example": "RECORDINGS_MISSING",
            "description": "Stable code — never renumbered."
          },
          "action": {
            "type": "string",
            "description": "What to do, in the words a customer would use — and the only prose here. The gate’s own wording used to sit beside it under `message`; the two were written for different people, and a caller quoting the wrong one made a customer hear the engineer. Branch on `code`, quote `action`."
          },
          "room": {
            "type": "string",
            "example": "record",
            "description": "Dashboard room that fixes it."
          },
          "fixableBy": {
            "type": "string",
            "enum": [
              "agent",
              "human"
            ],
            "description": "`human` cannot be done over this API at all — filming needs a camera. Everything else you can fix yourself; handing it to a person would be asking them to do your job."
          },
          "url": {
            "type": "string",
            "format": "uri"
          }
        },
        "required": [
          "code",
          "action",
          "room",
          "fixableBy",
          "url"
        ]
      },
      "ReadinessResponseDto": {
        "type": "object",
        "properties": {
          "publishable": {
            "type": "boolean",
            "description": "True when POST /publish would succeed. Nothing is written to find out."
          },
          "steps": {
            "description": "Everything still in the way.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HandoffStepDto"
            }
          },
          "needsAHuman": {
            "description": "The subset needing a person. Empty means you can finish alone.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HandoffStepDto"
            }
          },
          "summary": {
            "type": "string",
            "example": "Not publishable yet — 2 things left to configure, and 1 that needs you (record)."
          }
        },
        "required": [
          "publishable",
          "steps",
          "needsAHuman",
          "summary"
        ]
      },
      "BulkSetQuestionDto": {
        "type": "object",
        "properties": {
          "questions": {
            "example": "Questions",
            "description": "Questions",
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "questions"
        ]
      },
      "BulkSetScoreDto": {
        "type": "object",
        "properties": {
          "scores": {
            "description": "Array of scores to create",
            "items": {
              "type": "array",
              "items": {
                "type": "a"
              }
            },
            "type": "array"
          }
        },
        "required": [
          "scores"
        ]
      },
      "FilterDto": {
        "type": "object",
        "properties": {
          "property": {
            "type": "string",
            "example": "user.age",
            "description": "Property path to filter on"
          },
          "type": {
            "type": "string",
            "example": "number",
            "description": "Type of the property being filtered",
            "enum": [
              "date",
              "number",
              "select",
              "multiselect",
              "boolean",
              "text"
            ]
          },
          "operation": {
            "type": "string",
            "example": "greaterThan",
            "description": "Operation to perform on the property",
            "enum": [
              "equals",
              "before",
              "after",
              "greaterThan",
              "lessThan",
              "greaterThanOrEqual",
              "lessThanOrEqual",
              "between",
              "notEquals",
              "isEmpty",
              "isNotEmpty",
              "contains",
              "notContains",
              "startsWith",
              "endsWith",
              "containsAll",
              "containsAny",
              "anyOf",
              "allOf",
              "noneOf"
            ]
          },
          "value": {
            "type": "object",
            "example": 25,
            "description": "Value to compare against. Can be Date, string, number, boolean, or string[]"
          },
          "and": {
            "description": "Nested filters for AND logical grouping",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FilterDto"
            }
          },
          "or": {
            "description": "Nested filters for OR logical grouping",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FilterDto"
            }
          }
        }
      },
      "PublicSegmentOptionDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "507f1f77bcf86cd799439010",
            "description": "ID of the segment option (for updates)"
          },
          "name": {
            "type": "string",
            "example": "High Value Customer",
            "description": "Name of the segment option"
          },
          "key": {
            "type": "string",
            "example": "high_value",
            "description": "Key identifier for the segment option"
          },
          "notes": {
            "type": "string",
            "example": "Customers with high lifetime value",
            "description": "Notes about this segment option"
          },
          "isFallback": {
            "type": "boolean",
            "example": false,
            "description": "Whether this is a fallback option",
            "default": false
          },
          "conditions": {
            "example": {
              "minScore": 80,
              "category": "premium"
            },
            "description": "Conditions for this segment option",
            "allOf": [
              {
                "$ref": "#/components/schemas/FilterDto"
              }
            ]
          },
          "redirectUrl": {
            "type": "string",
            "example": "https://example.com/redirect",
            "description": "Optional redirect URL for this segment option"
          },
          "redirectLabel": {
            "type": "string",
            "example": "Learn More",
            "description": "Label text for the redirect button/link"
          }
        },
        "required": [
          "name"
        ]
      },
      "PublicSegmentDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "507f1f77bcf86cd799439011",
            "description": "ID of the segment (for updates)"
          },
          "name": {
            "type": "string",
            "example": "Customer Segmentation",
            "description": "Name of the segment"
          },
          "slug": {
            "type": "string",
            "example": "customer-segmentation",
            "description": "Slug identifier for the segment"
          },
          "type": {
            "type": "string",
            "example": "segment",
            "description": "Type of the segment (segment or links)",
            "enum": [
              "segment",
              "links"
            ],
            "default": "segment"
          },
          "description": {
            "type": "string",
            "example": "Segments customers based on behavior",
            "description": "Description of the segment"
          },
          "order": {
            "type": "number",
            "example": 1,
            "description": "Order of the segment in the funnel"
          },
          "pageId": {
            "type": "string",
            "example": "507f1f77bcf86cd799439011",
            "description": "ID of the page this segment is associated with"
          },
          "hasRedirectUrl": {
            "type": "boolean",
            "example": false,
            "description": "Whether this segment contains redirect URLs",
            "default": false
          },
          "isSkipped": {
            "type": "boolean",
            "example": false,
            "description": "Whether this segment is skipped during diagnostic processing",
            "default": false
          },
          "metadata": {
            "type": "object",
            "example": {
              "key": "value"
            },
            "description": "Metadata for the segment"
          },
          "options": {
            "description": "The scene’s options.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicSegmentOptionDto"
            }
          },
          "pageSlug": {
            "type": "string",
            "example": "page-1",
            "description": "Slug of the result page this scene plays over. Use this rather than `pageId`: page ids are regenerated every time the draft is saved, slugs are not. Ignored if `pageId` is also given."
          }
        },
        "required": [
          "name",
          "order",
          "options"
        ]
      },
      "PublicBulkSetSegmentDto": {
        "type": "object",
        "properties": {
          "segments": {
            "description": "The complete scene set.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicSegmentDto"
            }
          }
        },
        "required": [
          "segments"
        ]
      },
      "ClipIdentifierDto": {
        "type": "object",
        "properties": {}
      },
      "GenerateScriptsDto": {
        "type": "object",
        "properties": {
          "clips": {
            "description": "Specific clips to generate scripts for. If omitted, generates for all non-skipped segment options.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClipIdentifierDto"
            }
          }
        }
      },
      "HtmlBlockDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The block, as self-contained HTML + CSS. Each block renders in its own shadow root, so selectors cannot leak between blocks and a bare `h2 { … }` is safe. What does cross that boundary is inheritance: font-family, color and line-height come in from the page unless the block sets them. The block clips whatever does not fit its height — see gridH.",
            "example": "<style>.card{padding:24px;font-family:sans-serif}</style><div class=\"card\"><h2>Your plan</h2></div>"
          },
          "gridX": {
            "type": "number",
            "description": "Snap-grid placement. Omitted, the block spans the full width at the top — a deliberate default, because a block that lands somewhere arbitrary reads as a bug while one that spans the row reads as a default."
          },
          "gridY": {
            "type": "number"
          },
          "gridW": {
            "type": "number"
          },
          "gridH": {
            "type": "number"
          },
          "label": {
            "type": "string",
            "description": "Name shown in the editor's layer list. Defaults to `Custom HTML`.",
            "example": "Archetype card"
          }
        },
        "required": [
          "code"
        ]
      },
      "CreateHtmlBlocksDto": {
        "type": "object",
        "properties": {
          "blocks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HtmlBlockDto"
            }
          },
          "answers": {
            "type": "object",
            "description": "Answers to render the returned preview for, keyed by question slug. Without them the preview shows the page with no lead behind it, which is rarely what you want to look at.",
            "additionalProperties": true
          },
          "orientation": {
            "type": "string",
            "enum": [
              "vertical",
              "horizontal"
            ],
            "description": "The video format your blocks are written for. Portrait is 36x64 grid cells, landscape 64x36, so a block sized for one does not work in the other. Only takes effect on a custom whose format is not settled yet — it then becomes the custom's format, and the editor stops asking. Asking for the other format on a settled custom is an error, not a switch: blocks already placed are measured against the current grid. Defaults to portrait."
          }
        },
        "required": [
          "blocks"
        ]
      },
      "HtmlBlocksCreatedDto": {
        "type": "object",
        "properties": {
          "pageSlug": {
            "type": "string",
            "example": "result"
          },
          "orientation": {
            "type": "string",
            "enum": [
              "vertical",
              "horizontal"
            ],
            "description": "The format the blocks were laid out against, and the one the custom is now settled on. Returned because it may not be what you asked for: on a custom whose format was already chosen, that choice wins.",
            "example": "vertical"
          },
          "nodeIds": {
            "description": "The nodes created, in order. Stable handles: page rows are regenerated on every save, node ids are not.",
            "example": [
              "9X3n4zd_or"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "previewUrl": {
            "type": "object",
            "nullable": true,
            "description": "A link to the page as it now renders. Null when no answers were given — there is nothing to resolve the page against."
          }
        },
        "required": [
          "pageSlug",
          "orientation",
          "nodeIds",
          "previewUrl"
        ]
      },
      "CreateResultPagePreviewDto": {
        "type": "object",
        "properties": {
          "answers": {
            "type": "object",
            "description": "The answers to preview for, keyed by question slug. Read the custom first — slugs are regenerated on every question write, so never hold one.",
            "example": {
              "q-mqao7ze9-x7ck0": "opt-mqao7ze9-dkwp0",
              "q-mqao7ze9-bvjs3": "4"
            },
            "additionalProperties": true
          },
          "version": {
            "type": "string",
            "description": "Which version to look at. Defaults to the draft — the work being checked. `active` is the published one.",
            "example": "draft"
          },
          "orientation": {
            "type": "string",
            "description": "Render portrait or landscape. Defaults to whatever the custom is authored in, which is what its leads will see — set this only to look at it the other way round.",
            "enum": [
              "vertical",
              "horizontal"
            ],
            "example": "horizontal"
          }
        },
        "required": [
          "answers"
        ]
      },
      "ResultPagePreviewPageDto": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string",
            "example": "page-1"
          },
          "name": {
            "type": "object",
            "nullable": true,
            "example": "Your plan"
          }
        },
        "required": [
          "slug",
          "name"
        ]
      },
      "ResultPagePreviewDto": {
        "type": "object",
        "properties": {
          "previewUrl": {
            "type": "string",
            "description": "Open this to see the page. Single-use in practice: it stops working at `expiresAt`.",
            "example": "https://app.custom.one/page-result/6aab8c14f7421774f75d5865?t=5YKrHPmn…"
          },
          "expiresAt": {
            "type": "string",
            "description": "When the link stops working. Ask for a new one rather than holding this.",
            "example": "2026-09-18T14:00:00.000Z"
          },
          "pages": {
            "description": "The pages this set of answers produced, in order. Add `?page=<slug>` to the URL to open one directly.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ResultPagePreviewPageDto"
            }
          }
        },
        "required": [
          "previewUrl",
          "expiresAt",
          "pages"
        ]
      },
      "CreateHookDto": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "example": "https://hook.eu1.make.com/abc123",
            "description": "Target URL the events are POSTed to (https only)"
          },
          "events": {
            "type": "array",
            "example": [
              "diagnostic.submitted"
            ],
            "items": {
              "type": "string",
              "enum": [
                "diagnostic.submitted",
                "diagnostic.completed",
                "lead.video_started",
                "lead.video_watched",
                "lead.cta_clicked",
                "lead.purchased",
                "email.confirmation_sent",
                "email.result_sent",
                "sms.result_sent"
              ]
            }
          },
          "funnelId": {
            "type": "string",
            "description": "Scope to one funnel. Omit to receive events for every funnel of the workspace."
          },
          "source": {
            "type": "string",
            "enum": [
              "make",
              "zapier",
              "n8n",
              "api"
            ],
            "default": "api",
            "description": "Which platform is subscribing (for display in the dashboard)"
          },
          "includeImportedLeads": {
            "type": "boolean",
            "default": false,
            "description": "Also receive events for imported leads (created via API/external sources). Off by default to prevent automation loops."
          }
        },
        "required": [
          "url",
          "events"
        ]
      },
      "HookDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "6a841c7184a9e48e2ee80600"
          },
          "url": {
            "type": "string",
            "example": "https://hook.eu1.make.com/abc123"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "diagnostic.submitted",
                "diagnostic.completed",
                "lead.video_started",
                "lead.video_watched",
                "lead.cta_clicked",
                "lead.purchased",
                "email.confirmation_sent",
                "email.result_sent",
                "sms.result_sent"
              ]
            }
          },
          "funnelId": {
            "type": "object",
            "nullable": true,
            "description": "Scoped funnel, or null for workspace-wide."
          },
          "source": {
            "type": "string",
            "enum": [
              "make",
              "zapier",
              "n8n",
              "api"
            ],
            "nullable": true
          },
          "includeImportedLeads": {
            "type": "boolean"
          },
          "isActive": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "url",
          "events",
          "funnelId",
          "source",
          "includeImportedLeads",
          "isActive",
          "createdAt"
        ]
      },
      "HookListResponseDto": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/HookDto"
            }
          }
        },
        "required": [
          "data"
        ]
      },
      "UpdateHookDto": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "example": "https://hook.eu1.make.com/abc123",
            "description": "New target URL (https only)."
          },
          "events": {
            "type": "array",
            "description": "REPLACES the subscribed set — send the full list you want, not a delta.",
            "items": {
              "type": "string",
              "enum": [
                "diagnostic.submitted",
                "diagnostic.completed",
                "lead.video_started",
                "lead.video_watched",
                "lead.cta_clicked",
                "lead.purchased",
                "email.confirmation_sent",
                "email.result_sent",
                "sms.result_sent"
              ]
            }
          },
          "funnelId": {
            "type": "object",
            "nullable": true,
            "description": "Scope to one funnel, or send `null` to receive events for every funnel of the workspace."
          },
          "includeImportedLeads": {
            "type": "boolean",
            "description": "Also receive events for imported leads (off by default, prevents automation loops)."
          },
          "isActive": {
            "type": "boolean",
            "description": "Pause a subscription without losing it. A paused hook receives nothing."
          }
        }
      },
      "FieldMappingDto": {
        "type": "object",
        "properties": {
          "sourcePath": {
            "type": "string",
            "example": "contact.email",
            "description": "Dotted path into the incoming payload"
          },
          "questionSlug": {
            "type": "string",
            "example": "email",
            "description": "Question slug on the funnel that this payload field fills"
          }
        },
        "required": [
          "sourcePath",
          "questionSlug"
        ]
      },
      "CreateSourceDto": {
        "type": "object",
        "properties": {
          "funnelId": {
            "type": "string",
            "description": "Funnel this source feeds. Cannot be changed afterwards."
          },
          "name": {
            "type": "string",
            "example": "HubSpot lead form",
            "description": "Shown in the dashboard next to the rows it produced."
          },
          "type": {
            "type": "string",
            "enum": [
              "webhook",
              "csv"
            ],
            "default": "webhook",
            "description": "What kind of pipe this is. `webhook` gets an ingest URL the customer pastes into their own tool. `csv` is a container for file imports — **`POST /sources/:id/import` only accepts a `csv` source** and refuses a webhook one. Pick the type up front; it cannot be changed afterwards."
          },
          "fieldMappings": {
            "description": "Maps dotted paths in the incoming payload onto question slugs. May be empty and configured later — unmapped keys that already match a slug still resolve. Read `GET /funnels/:id/fields` for the slugs.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FieldMappingDto"
            }
          },
          "isActive": {
            "type": "boolean",
            "default": true
          },
          "autoSubmit": {
            "type": "boolean",
            "default": false,
            "description": "⚠️ COSTS MONEY. When true, every payload that arrives becomes a lead immediately: a result video renders and the follow-ups fire, billed against the plan. When false (the default) payloads land as PENDING rows a human reviews in the dashboard first. Leave it off unless the customer has explicitly asked for hands-off ingestion."
          }
        },
        "required": [
          "funnelId",
          "name"
        ]
      },
      "SourceSecretResponseDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "secret": {
            "type": "string",
            "description": "Bearer secret embedded in the ingest URL. Treat it as a credential."
          },
          "ingestUrl": {
            "type": "string",
            "format": "uri",
            "description": "Paste-ready endpoint for the customer’s own tool. This is the deliverable — hand this over, not the secret on its own.",
            "example": "https://api.custom.one/public/external-sources/6a84…/ingest/abc123"
          }
        },
        "required": [
          "id",
          "secret",
          "ingestUrl"
        ]
      },
      "SourceFieldMappingDto": {
        "type": "object",
        "properties": {
          "sourcePath": {
            "type": "string",
            "example": "contact.email"
          },
          "questionSlug": {
            "type": "string",
            "example": "default-contact-form__email"
          }
        },
        "required": [
          "sourcePath",
          "questionSlug"
        ]
      },
      "SourceDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "6a841c7184a9e48e2ee80600"
          },
          "funnelId": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "example": "HubSpot lead form"
          },
          "type": {
            "type": "string",
            "enum": [
              "webhook",
              "csv"
            ],
            "example": "webhook",
            "description": "Fixed at creation."
          },
          "fieldMappings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SourceFieldMappingDto"
            }
          },
          "isActive": {
            "type": "boolean"
          },
          "autoSubmit": {
            "type": "boolean",
            "description": "⚠️ When true every arriving payload renders a billable video."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "funnelId",
          "name",
          "type",
          "fieldMappings",
          "isActive",
          "autoSubmit",
          "createdAt"
        ]
      },
      "SourceListResponseDto": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SourceDto"
            }
          }
        },
        "required": [
          "data"
        ]
      },
      "UpdateSourceDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "fieldMappings": {
            "description": "REPLACES the mapping set.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FieldMappingDto"
            }
          },
          "isActive": {
            "type": "boolean",
            "description": "An inactive source rejects incoming payloads without deleting anything."
          },
          "autoSubmit": {
            "type": "boolean",
            "description": "⚠️ COSTS MONEY — see the same field on create."
          }
        }
      },
      "ImportCsvDto": {
        "type": "object",
        "properties": {
          "csv": {
            "type": "string",
            "description": "Raw CSV including its header row. The header must carry question slugs or their labels — the same names `GET /funnels/:id/fields` returns. The source must have been created with `type: \"csv\"`; a webhook source refuses this with a 400.",
            "example": "email,firstname,q-abc123\\nlead@example.com,Jane,option-a\\n"
          }
        },
        "required": [
          "csv"
        ]
      },
      "CsvImportResponseDto": {
        "type": "object",
        "properties": {
          "totalRows": {
            "type": "number",
            "description": "Rows found in the file, header excluded."
          },
          "imported": {
            "type": "number",
            "description": "Rows persisted as PENDING. They are NOT leads yet — a human submits them, or autoSubmit does."
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Per-row failures as { rowIndex, message }. A partial import is a success with errors, not a rollback."
          }
        },
        "required": [
          "totalRows",
          "imported",
          "errors"
        ]
      },
      "LeadContactDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "6a8424587351f8d06da3fa38"
          },
          "email": {
            "type": "object",
            "nullable": true,
            "example": "lead@example.com"
          },
          "firstname": {
            "type": "object",
            "nullable": true,
            "example": "Jane"
          },
          "lastname": {
            "type": "object",
            "nullable": true
          },
          "phone": {
            "type": "object",
            "nullable": true,
            "example": "+33600000000"
          }
        },
        "required": [
          "id",
          "email",
          "firstname",
          "lastname",
          "phone"
        ]
      },
      "LeadListItemDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "6a8424587351f8d06da3fa37"
          },
          "funnelId": {
            "type": "object",
            "nullable": true
          },
          "status": {
            "type": "string",
            "description": "Pipeline state of the lead and its video.",
            "example": "COMPLETED"
          },
          "source": {
            "type": "object",
            "nullable": true,
            "description": "Where the lead came in from: null for the public quiz, `external` for the API or an inbound source.",
            "example": "external"
          },
          "isBot": {
            "type": "boolean",
            "description": "Flagged as bot traffic. Not filtered out — decide for yourself."
          },
          "productPurchased": {
            "type": "boolean"
          },
          "notes": {
            "type": "object",
            "nullable": true
          },
          "contact": {
            "nullable": true,
            "allOf": [
              {
                "$ref": "#/components/schemas/LeadContactDto"
              }
            ]
          },
          "resultUrl": {
            "type": "object",
            "format": "uri",
            "nullable": true,
            "example": "https://forms.custom.one/result/6a8424587351f8d06da3fa37"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "submittedAt": {
            "type": "object",
            "format": "date-time",
            "nullable": true
          }
        },
        "required": [
          "id",
          "funnelId",
          "status",
          "source",
          "isBot",
          "productPurchased",
          "notes",
          "contact",
          "resultUrl",
          "createdAt",
          "submittedAt"
        ]
      },
      "LeadListResponseDto": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LeadListItemDto"
            }
          },
          "nextCursor": {
            "type": "object",
            "nullable": true,
            "description": "Pass as `cursor` for the next page. **`null` is the only signal that you have everything** — a short page does not mean the end, and a full page does not mean there is more.",
            "example": "6a8424587351f8d06da3fa37"
          }
        },
        "required": [
          "data",
          "nextCursor"
        ]
      },
      "CreateLeadDto": {
        "type": "object",
        "properties": {
          "funnelId": {
            "type": "string",
            "description": "Funnel to create the lead in (must be published)"
          },
          "replies": {
            "type": "object",
            "description": "Answers keyed by question slug. SELECT/MULTISELECT accept option slugs or labels.",
            "example": {
              "q-abc123-x1": "Sédentaire, zéro activité",
              "q-abc123-x2": 4
            }
          },
          "contact": {
            "type": "object",
            "description": "Contact fields — mapped automatically onto the funnel’s CONTACT question.",
            "example": {
              "email": "lead@example.com",
              "firstname": "Jane",
              "phone": "+33600000000"
            }
          },
          "generateVideo": {
            "type": "boolean",
            "default": true,
            "description": "Generate the personalized result video (counts toward the workspace plan / overage). Defaults to true."
          }
        },
        "required": [
          "funnelId",
          "replies"
        ]
      },
      "RejectedFieldDto": {
        "type": "object",
        "properties": {
          "field": {
            "type": "string",
            "description": "The `replies` key that was refused.",
            "example": "q-a1b2c3"
          },
          "reason": {
            "type": "string",
            "description": "Why it was refused, in terms the caller can act on.",
            "example": "value is not one of the options of this question"
          }
        },
        "required": [
          "field",
          "reason"
        ]
      },
      "CreateLeadResponseDto": {
        "type": "object",
        "properties": {
          "diagnosticId": {
            "type": "string",
            "description": "The created lead (diagnostic) id.",
            "example": "6a8424587351f8d06da3fa37"
          },
          "resultUrl": {
            "type": "string",
            "format": "uri",
            "example": "https://forms.custom.one/result/6a8424587351f8d06da3fa37"
          },
          "videoGeneration": {
            "type": "string",
            "enum": [
              "queued",
              "skipped"
            ],
            "description": "Whether a result video was queued."
          },
          "rejectedFields": {
            "description": "Fields that matched a question but whose value was refused. The lead WAS created, without them — this is a partial success, not a failure. Omitted entirely when everything landed, so a clean create keeps its shape. Fix these and PATCH the lead.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RejectedFieldDto"
            }
          },
          "replayed": {
            "type": "boolean",
            "description": "Present and true when this was an idempotent replay (no new lead created)."
          }
        },
        "required": [
          "diagnosticId",
          "resultUrl",
          "videoGeneration"
        ]
      },
      "SampleLeadsResponseDto": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Recent leads shaped exactly like the `diagnostic.submitted` webhook payload (event, workspaceId, timestamp, data: { diagnostic, contact, repliesBySlug, resultUrl }). Used by platform apps to preview a trigger."
          }
        },
        "required": [
          "data"
        ]
      },
      "UpdateLeadDto": {
        "type": "object",
        "properties": {
          "productPurchased": {
            "type": "boolean",
            "description": "Mark the lead as having purchased. false→true fires lead.purchased."
          },
          "notes": {
            "type": "string",
            "description": "Free-text note stored on the lead."
          }
        }
      },
      "UpdateLeadResponseDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "6a8424587351f8d06da3fa37"
          },
          "notes": {
            "type": "object",
            "nullable": true
          },
          "productPurchased": {
            "type": "boolean"
          }
        },
        "required": [
          "id",
          "notes",
          "productPurchased"
        ]
      },
      "TagDto": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "example": "Customer"
          },
          "color": {
            "type": "object",
            "nullable": true,
            "example": "#5490FF"
          }
        },
        "required": [
          "id",
          "name",
          "color"
        ]
      },
      "TagListResponseDto": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TagDto"
            }
          }
        },
        "required": [
          "data"
        ]
      },
      "LeadTagsDto": {
        "type": "object",
        "properties": {
          "tags": {
            "example": [
              "Customer",
              "VIP"
            ],
            "description": "Tag names to add/remove on the lead’s contact. On add, unknown names are created automatically.",
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "tags"
        ]
      },
      "LeadTagsResponseDto": {
        "type": "object",
        "properties": {
          "leadId": {
            "type": "string",
            "example": "6a8424587351f8d06da3fa37"
          },
          "tags": {
            "example": [
              "Customer"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "leadId",
          "tags"
        ]
      }
    }
  }
}
