{
  "components": {
    "schemas": {
      "Actor": {
        "description": "Who performed the audited action. Append-only provenance record.\nPortal variants carry the client-side tier so audit trails distinguish\nstaff actions from client-portal actions at the storage layer\n(actor_kind portal_contact / portal_approver / portal_it_manager).",
        "oneOf": [
          {
            "properties": {
              "id": {
                "format": "uuid",
                "type": "string"
              },
              "kind": {
                "enum": [
                  "human"
                ],
                "type": "string"
              }
            },
            "required": [
              "id",
              "kind"
            ],
            "type": "object"
          },
          {
            "properties": {
              "id": {
                "type": "string"
              },
              "kind": {
                "enum": [
                  "agent"
                ],
                "type": "string"
              }
            },
            "required": [
              "id",
              "kind"
            ],
            "type": "object"
          },
          {
            "properties": {
              "id": {
                "type": "string"
              },
              "kind": {
                "enum": [
                  "plugin"
                ],
                "type": "string"
              }
            },
            "required": [
              "id",
              "kind"
            ],
            "type": "object"
          },
          {
            "properties": {
              "id": {
                "type": "string"
              },
              "kind": {
                "enum": [
                  "connector"
                ],
                "type": "string"
              }
            },
            "required": [
              "id",
              "kind"
            ],
            "type": "object"
          },
          {
            "properties": {
              "kind": {
                "enum": [
                  "system"
                ],
                "type": "string"
              }
            },
            "required": [
              "kind"
            ],
            "type": "object"
          },
          {
            "properties": {
              "id": {
                "format": "uuid",
                "type": "string"
              },
              "kind": {
                "enum": [
                  "portal_contact"
                ],
                "type": "string"
              }
            },
            "required": [
              "id",
              "kind"
            ],
            "type": "object"
          },
          {
            "properties": {
              "id": {
                "format": "uuid",
                "type": "string"
              },
              "kind": {
                "enum": [
                  "portal_approver"
                ],
                "type": "string"
              }
            },
            "required": [
              "id",
              "kind"
            ],
            "type": "object"
          },
          {
            "properties": {
              "id": {
                "format": "uuid",
                "type": "string"
              },
              "kind": {
                "enum": [
                  "portal_it_manager"
                ],
                "type": "string"
              }
            },
            "required": [
              "id",
              "kind"
            ],
            "type": "object"
          },
          {
            "description": "Bulk-import runs (TASKLIST D2): the descriptor names the driving\nidentity without pretending it row-walked — `\"user:<uuid>\"` for\nadmin JWT runs, `\"api-key:<key-id>\"\"` for machine pushes. Row-level\nmutations still emit their ordinary domain events; the import actor\nowns batch-lifecycle provenance (kind \"import\" in audit storage).",
            "properties": {
              "id": {
                "description": "Bulk-import runs (TASKLIST D2): the descriptor names the driving\nidentity without pretending it row-walked — `\"user:<uuid>\"` for\nadmin JWT runs, `\"api-key:<key-id>\"\"` for machine pushes. Row-level\nmutations still emit their ordinary domain events; the import actor\nowns batch-lifecycle provenance (kind \"import\" in audit storage).",
                "type": "string"
              },
              "kind": {
                "enum": [
                  "import"
                ],
                "type": "string"
              }
            },
            "required": [
              "id",
              "kind"
            ],
            "type": "object"
          }
        ]
      },
      "AddChecklistItemRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1): idempotency key + entity\nversion. Absent in legacy clients — purely additive."
          },
          {
            "properties": {
              "text": {
                "type": "string"
              }
            },
            "required": [
              "text"
            ],
            "type": "object"
          }
        ]
      },
      "AddCommentRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1): idempotency key. Absent in\nlegacy clients — purely additive. (Comments are fresh entities, so\nthere is no version to match.)"
          },
          {
            "properties": {
              "attachment_ids": {
                "description": "Attachments uploaded earlier against this ticket (composer flow:\nupload first, link when the comment is created). Absent/empty in\nolder clients — purely additive.",
                "items": {
                  "format": "uuid",
                  "type": "string"
                },
                "type": "array"
              },
              "body": {
                "type": "string"
              },
              "kind": {
                "$ref": "#/components/schemas/NoteKind"
              }
            },
            "required": [
              "body",
              "kind"
            ],
            "type": "object"
          }
        ]
      },
      "AgentProposalPage": {
        "description": "GET /api/agent-proposals envelope.",
        "properties": {
          "next_cursor": {
            "type": [
              "string",
              "null"
            ]
          },
          "proposals": {
            "items": {
              "$ref": "#/components/schemas/AgentProposalView"
            },
            "type": "array"
          }
        },
        "required": [
          "proposals"
        ],
        "type": "object"
      },
      "AgentProposalView": {
        "description": "One IF8 proposal with the full snapshot the approval decision needs.",
        "properties": {
          "agent_kind": {
            "type": "string"
          },
          "agent_ref": {
            "type": "string"
          },
          "applied_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "base_version": {
            "description": "The entity write-seq the proposal was created against.",
            "format": "int64",
            "type": "integer"
          },
          "before_value": {
            "description": "The value the agent saw (`null` when the record did not exist).",
            "type": [
              "object",
              "null"
            ]
          },
          "capability": {
            "type": [
              "string",
              "null"
            ]
          },
          "classification": {
            "$ref": "#/components/schemas/ProposalClassification"
          },
          "created_at": {
            "type": "string"
          },
          "decided_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "decided_by": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "decision_note": {
            "type": [
              "string",
              "null"
            ]
          },
          "dial_mode": {
            "$ref": "#/components/schemas/CapabilityMode",
            "description": "Involvement-dial snapshot at proposal time."
          },
          "entity": {
            "description": "Record coordinates (v1 applies `ticket`/`update` only; the store is\ngeneric).",
            "type": "string"
          },
          "entity_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "for_user": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "op": {
            "type": "string"
          },
          "proposed_value": {
            "description": "The proposed after value.",
            "type": "object"
          },
          "rationale": {
            "type": [
              "string",
              "null"
            ]
          },
          "rule_set_hash": {
            "type": [
              "string",
              "null"
            ]
          },
          "session_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "skill_slug": {
            "type": [
              "string",
              "null"
            ]
          },
          "skill_version": {
            "format": "int32",
            "type": [
              "integer",
              "null"
            ]
          },
          "status": {
            "$ref": "#/components/schemas/ProposalStatus"
          },
          "tool": {
            "type": [
              "string",
              "null"
            ]
          },
          "updated_at": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "entity",
          "op",
          "before_value",
          "proposed_value",
          "classification",
          "dial_mode",
          "base_version",
          "status",
          "agent_kind",
          "agent_ref",
          "created_at",
          "updated_at"
        ],
        "type": "object"
      },
      "AgentSkillList": {
        "properties": {
          "skills": {
            "items": {
              "$ref": "#/components/schemas/AgentSkillView"
            },
            "type": "array"
          }
        },
        "required": [
          "skills"
        ],
        "type": "object"
      },
      "AgentSkillView": {
        "description": "One immutable skill version.",
        "properties": {
          "created_at": {
            "type": "string"
          },
          "created_by": {
            "format": "uuid",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "manifest": {
            "description": "`{capabilities, prompts, rules}` — declarative manifest (§4).",
            "type": "object"
          },
          "slug": {
            "type": "string"
          },
          "version": {
            "format": "int32",
            "type": "integer"
          }
        },
        "required": [
          "id",
          "slug",
          "version",
          "manifest",
          "created_by",
          "created_at"
        ],
        "type": "object"
      },
      "Aggregate": {
        "description": "Aggregation function of a measure. `Count` may omit the column\n(`COUNT(*)`); every other aggregate requires one, and the catalog\ndecides which column types each accepts.",
        "enum": [
          "count",
          "sum",
          "avg",
          "min",
          "max"
        ],
        "type": "string"
      },
      "AlertListQuery": {
        "properties": {
          "limit": {
            "format": "int64",
            "type": "integer"
          },
          "offset": {
            "format": "int64",
            "type": "integer"
          },
          "source_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "ticket_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "AlertListResponse": {
        "properties": {
          "alerts": {
            "items": {
              "$ref": "#/components/schemas/AlertView"
            },
            "type": "array"
          }
        },
        "required": [
          "alerts"
        ],
        "type": "object"
      },
      "AlertSeverity": {
        "description": "Alert severity vocabulary. Maps onto ticket priorities when an alert\nanchors an incident ticket: critical→P1, warning→P2, info→P3.",
        "enum": [
          "info",
          "warning",
          "critical"
        ],
        "type": "string"
      },
      "AlertSourceList": {
        "properties": {
          "sources": {
            "items": {
              "$ref": "#/components/schemas/AlertSourceView"
            },
            "type": "array"
          }
        },
        "required": [
          "sources"
        ],
        "type": "object"
      },
      "AlertSourceMutationResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AlertSourceView"
          },
          {
            "properties": {
              "mutation": {
                "$ref": "#/components/schemas/MutationMeta"
              },
              "secret": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "mutation"
            ],
            "type": "object"
          }
        ],
        "description": "Instant-first mutation response for a source (IF2). `secret` is the\nraw HMAC signing secret — populated ONLY by the create response and\nnever again (same show-once contract as webhooks/api-keys)."
      },
      "AlertSourceView": {
        "description": "An ingest source as the admin surface sees it. The HMAC secret is\nNEVER here — it is returned exactly once, in the create response.",
        "properties": {
          "board_id": {
            "format": "uuid",
            "type": "string"
          },
          "client_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "correlation_window_secs": {
            "format": "int32",
            "type": "integer"
          },
          "created_at": {
            "type": "string"
          },
          "enabled": {
            "type": "boolean"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "source_ref": {
            "description": "Path segment of the ingest URL (public routing id).",
            "type": "string"
          },
          "updated_at": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "name",
          "source_ref",
          "board_id",
          "correlation_window_secs",
          "enabled",
          "created_at",
          "updated_at"
        ],
        "type": "object"
      },
      "AlertView": {
        "description": "One normalized alert (canonical ingest document + ledger row view).",
        "properties": {
          "attributes": {
            "type": "object"
          },
          "correlation_key": {
            "description": "Storm grouping key (defaults to the dedup key server-side).",
            "type": "string"
          },
          "dedup_key": {
            "description": "Provider's per-event identity; the replay gate per source.",
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "incident_ticket_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "occurred_at": {
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "received_at": {
            "type": "string"
          },
          "severity": {
            "type": "string"
          },
          "source_id": {
            "format": "uuid",
            "type": "string"
          },
          "title": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "source_id",
          "dedup_key",
          "correlation_key",
          "title",
          "severity",
          "occurred_at",
          "attributes",
          "received_at"
        ],
        "type": "object"
      },
      "ApiKeyCreatedResponse": {
        "description": "The ONLY response carrying raw key material. Lost keys are rotated by\ncreating a new key and revoking this one — never recovered.",
        "properties": {
          "key": {
            "$ref": "#/components/schemas/ApiKeyView"
          },
          "raw_key": {
            "description": "Raw bearer material: `mrd_<32 hex>`.",
            "type": "string"
          }
        },
        "required": [
          "key",
          "raw_key"
        ],
        "type": "object"
      },
      "ApiKeyList": {
        "properties": {
          "keys": {
            "items": {
              "$ref": "#/components/schemas/ApiKeyView"
            },
            "type": "array"
          }
        },
        "required": [
          "keys"
        ],
        "type": "object"
      },
      "ApiKeyView": {
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "last_used_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "type": "string"
          },
          "prefix": {
            "description": "Non-secret display prefix, e.g. \"mrd_ab12cd34\".",
            "type": "string"
          },
          "revoked_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "scopes": {
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "required": [
          "id",
          "name",
          "prefix",
          "scopes",
          "created_at"
        ],
        "type": "object"
      },
      "Appointment": {
        "description": "A booked slot on one user's calendar, optionally tied to a ticket and\nclient/site. `travel_minutes` is a dispatch-board placeholder — never\ninterpreted by scheduling rules in this stage.",
        "properties": {
          "client_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "ends_at": {
            "format": "date-time",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "kind": {
            "$ref": "#/components/schemas/AppointmentKind"
          },
          "notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "site_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "starts_at": {
            "format": "date-time",
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/AppointmentStatus"
          },
          "ticket_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "title": {
            "type": "string"
          },
          "travel_minutes": {
            "format": "int32",
            "type": "integer"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          },
          "user_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "user_id",
          "title",
          "starts_at",
          "ends_at",
          "kind",
          "status",
          "travel_minutes",
          "created_at",
          "updated_at"
        ],
        "type": "object"
      },
      "AppointmentKind": {
        "description": "What an appointment is physically for. Drives rendering color-coding on\ncalendars and future travel-time logic (on_site only).",
        "enum": [
          "on_site",
          "remote",
          "internal",
          "personal"
        ],
        "type": "string"
      },
      "AppointmentRequest": {
        "description": "A client's request for a slot on one staff member's calendar.",
        "properties": {
          "appointment_id": {
            "description": "The real booking created by approval (null until then).",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "client_id": {
            "format": "uuid",
            "type": "string"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "decided_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "decided_by": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "decision_note": {
            "description": "Note attached on approve/decline.",
            "type": [
              "string",
              "null"
            ]
          },
          "ends_at": {
            "format": "date-time",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "kind": {
            "$ref": "#/components/schemas/AppointmentKind"
          },
          "notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "portal_user_id": {
            "description": "The requesting portal identity (NOT a staff row).",
            "format": "uuid",
            "type": "string"
          },
          "starts_at": {
            "format": "date-time",
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/AppointmentRequestStatus"
          },
          "title": {
            "type": "string"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          },
          "user_id": {
            "description": "The staff member whose calendar was requested.",
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "client_id",
          "portal_user_id",
          "user_id",
          "title",
          "starts_at",
          "ends_at",
          "kind",
          "status",
          "created_at",
          "updated_at"
        ],
        "type": "object"
      },
      "AppointmentRequestListQuery": {
        "properties": {
          "limit": {
            "format": "int64",
            "type": "integer"
          },
          "offset": {
            "format": "int64",
            "type": "integer"
          },
          "status": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/AppointmentRequestStatus",
                "description": "Exact status: `pending | approved | declined | cancelled`."
              }
            ]
          }
        },
        "type": "object"
      },
      "AppointmentRequestStatus": {
        "description": "Lifecycle of an appointment request. `approved`/`declined`/`cancelled`\nare terminal; approved requests carry the created appointment's id.",
        "enum": [
          "pending",
          "approved",
          "declined",
          "cancelled"
        ],
        "type": "string"
      },
      "AppointmentStatus": {
        "description": "Lifecycle of a booking. `cancelled` frees the slot (the DB exclusion\nconstraint's partial predicate); `done` still occupies it.",
        "enum": [
          "scheduled",
          "in_progress",
          "done",
          "cancelled"
        ],
        "type": "string"
      },
      "ArticleListQuery": {
        "properties": {
          "category_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "client_visible": {
            "description": "Only articles passing the effective client-facing gate.",
            "type": "boolean"
          },
          "q": {
            "description": "Title substring narrowing; ranked full-text search rides /api/search.",
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/KbArticleStatus"
              }
            ]
          }
        },
        "type": "object"
      },
      "ArticleMutationResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/KbArticle"
          },
          {
            "properties": {
              "mutation": {
                "$ref": "#/components/schemas/MutationMeta"
              }
            },
            "required": [
              "mutation"
            ],
            "type": "object"
          }
        ],
        "description": "Instant-first mutation response (IF2)."
      },
      "AssignGroupRequest": {
        "properties": {
          "group_id": {
            "description": "`Some(group)` moves the board into that group; `None` ungroups it.",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "AssignRequest": {
        "properties": {
          "ends_at": {
            "format": "date-time",
            "type": "string"
          },
          "starts_at": {
            "format": "date-time",
            "type": "string"
          },
          "ticket_id": {
            "format": "uuid",
            "type": "string"
          },
          "travel_minutes": {
            "format": "int32",
            "type": "integer"
          },
          "user_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "ticket_id",
          "user_id",
          "starts_at",
          "ends_at"
        ],
        "type": "object"
      },
      "Attachment": {
        "description": "One uploaded file's metadata row; the payload lives behind `storage_key`.",
        "properties": {
          "content_type": {
            "description": "Declared + magic-byte-verified content type.",
            "type": "string"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "email_message_id": {
            "description": "Set only when kind is email_message.",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "filename": {
            "description": "Original filename, sanitized (no path components/control chars).",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "kind": {
            "$ref": "#/components/schemas/AttachmentKind"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "sha256": {
            "description": "Lowercase hex sha256 of the exact bytes; dedup + integrity anchor.",
            "type": "string"
          },
          "size_bytes": {
            "format": "int64",
            "type": "integer"
          },
          "storage_key": {
            "description": "Object-store key (`org/<id>/attachments/<sha256>`).",
            "type": "string"
          },
          "ticket_comment_id": {
            "description": "Set only when kind is ticket_comment.",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "ticket_id": {
            "description": "Set when kind is ticket_comment or ticket.",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "uploaded_by_portal_user_id": {
            "description": "Portal actor when uploaded through a portal surface (v1: none —\nreserved so portal uploads need no schema change).",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "uploaded_by_user_id": {
            "description": "Staff uploader when uploaded through the API.",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "org_id",
          "kind",
          "filename",
          "content_type",
          "size_bytes",
          "sha256",
          "storage_key",
          "created_at"
        ],
        "type": "object"
      },
      "AttachmentDeleted": {
        "description": "attachment.deleted — the metadata row went away; `object_removed`\nreports whether the backing bytes were reclaimed too (refcount hit 0).",
        "properties": {
          "attachment_id": {
            "format": "uuid",
            "type": "string"
          },
          "object_removed": {
            "type": "boolean"
          },
          "ticket_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "attachment_id",
          "object_removed"
        ],
        "type": "object"
      },
      "AttachmentKind": {
        "description": "What an attachment belongs to. The enum value is persisted verbatim.",
        "enum": [
          "ticket_comment",
          "email_message",
          "ticket"
        ],
        "type": "string"
      },
      "AuditEvent": {
        "properties": {
          "action": {
            "description": "Dot-path of the action, e.g. \"auth.login\", \"ticket.status_change\".",
            "type": "string"
          },
          "actor": {
            "$ref": "#/components/schemas/Actor"
          },
          "detail": {
            "description": "Structured detail — never contains secrets."
          },
          "entity_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "entity_type": {
            "description": "Entity type + id the action targeted, when applicable.",
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "ip": {
            "type": [
              "string",
              "null"
            ]
          },
          "occurred_at": {
            "format": "date-time",
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "actor",
          "action",
          "detail",
          "occurred_at"
        ],
        "type": "object"
      },
      "AuditPage": {
        "properties": {
          "events": {
            "items": {
              "$ref": "#/components/schemas/AuditEvent"
            },
            "type": "array"
          },
          "next_cursor": {
            "description": "Opaque cursor for the next page; absent when exhausted.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "events"
        ],
        "type": "object"
      },
      "AutomationAction": {
        "description": "Effects a rule may request. Every variant maps onto an existing core-api\nwrite path — automations never gain private write routes.",
        "oneOf": [
          {
            "properties": {
              "type": {
                "enum": [
                  "assign_user"
                ],
                "type": "string"
              },
              "user_id": {
                "format": "uuid",
                "type": "string"
              }
            },
            "required": [
              "user_id",
              "type"
            ],
            "type": "object"
          },
          {
            "properties": {
              "priority": {
                "$ref": "#/components/schemas/Priority"
              },
              "type": {
                "enum": [
                  "set_priority"
                ],
                "type": "string"
              }
            },
            "required": [
              "priority",
              "type"
            ],
            "type": "object"
          },
          {
            "properties": {
              "body": {
                "type": "string"
              },
              "type": {
                "enum": [
                  "add_internal_comment"
                ],
                "type": "string"
              }
            },
            "required": [
              "body",
              "type"
            ],
            "type": "object"
          },
          {
            "properties": {
              "kind": {
                "$ref": "#/components/schemas/NotificationKind"
              },
              "title": {
                "type": "string"
              },
              "type": {
                "enum": [
                  "notify_users"
                ],
                "type": "string"
              },
              "user_ids": {
                "items": {
                  "format": "uuid",
                  "type": "string"
                },
                "type": "array"
              }
            },
            "required": [
              "user_ids",
              "kind",
              "title",
              "type"
            ],
            "type": "object"
          }
        ]
      },
      "AutomationCondition": {
        "description": "One predicate; a rule matches only when EVERY condition holds.",
        "oneOf": [
          {
            "properties": {
              "priority": {
                "$ref": "#/components/schemas/Priority"
              },
              "type": {
                "enum": [
                  "priority_is"
                ],
                "type": "string"
              }
            },
            "required": [
              "priority",
              "type"
            ],
            "type": "object"
          },
          {
            "properties": {
              "category": {
                "$ref": "#/components/schemas/TicketStatusCategory"
              },
              "type": {
                "enum": [
                  "category_is"
                ],
                "type": "string"
              }
            },
            "required": [
              "category",
              "type"
            ],
            "type": "object"
          },
          {
            "properties": {
              "needle": {
                "type": "string"
              },
              "type": {
                "enum": [
                  "title_contains"
                ],
                "type": "string"
              }
            },
            "required": [
              "needle",
              "type"
            ],
            "type": "object"
          },
          {
            "description": "Assignee is currently unset.",
            "properties": {
              "type": {
                "enum": [
                  "unassigned"
                ],
                "type": "string"
              }
            },
            "required": [
              "type"
            ],
            "type": "object"
          }
        ]
      },
      "AvailabilityListResponse": {
        "properties": {
          "user_id": {
            "format": "uuid",
            "type": "string"
          },
          "windows": {
            "items": {
              "$ref": "#/components/schemas/AvailabilityWindow"
            },
            "type": "array"
          }
        },
        "required": [
          "user_id",
          "windows"
        ],
        "type": "object"
      },
      "AvailabilityQuery": {
        "properties": {
          "user_id": {
            "description": "Whose windows. Defaults to the caller; another user requires owner/admin.",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "AvailabilityWindow": {
        "description": "One recurring weekly availability template: `weekday` (0 = Monday …\n6 = Sunday), local wall-clock `[start_local, end_local)` in `timezone`,\noptionally bounded by an effective date range. This is a TEMPLATE —\noccurrences are computed, never stored.",
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "effective_from": {
            "type": [
              "string",
              "null"
            ]
          },
          "effective_until": {
            "type": [
              "string",
              "null"
            ]
          },
          "end_local": {
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "start_local": {
            "type": "string"
          },
          "timezone": {
            "description": "IANA timezone the wall-clock bounds live in.",
            "type": "string"
          },
          "user_id": {
            "format": "uuid",
            "type": "string"
          },
          "weekday": {
            "format": "int32",
            "type": "integer"
          }
        },
        "required": [
          "id",
          "org_id",
          "user_id",
          "weekday",
          "start_local",
          "end_local",
          "timezone",
          "created_at"
        ],
        "type": "object"
      },
      "BatchCreatedResponse": {
        "properties": {
          "batch_id": {
            "format": "uuid",
            "type": "string"
          },
          "label": {
            "type": "string"
          }
        },
        "required": [
          "batch_id",
          "label"
        ],
        "type": "object"
      },
      "BatchViewResponse": {
        "properties": {
          "conflict_policy": {
            "$ref": "#/components/schemas/ConflictPolicy"
          },
          "dry_run": {
            "type": "boolean"
          },
          "entity_kind": {
            "$ref": "#/components/schemas/EntityKind"
          },
          "finished_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "queued_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "rows_created": {
            "format": "int32",
            "type": "integer"
          },
          "rows_failed": {
            "format": "int32",
            "type": "integer"
          },
          "rows_skipped": {
            "format": "int32",
            "type": "integer"
          },
          "rows_total": {
            "format": "int32",
            "type": "integer"
          },
          "rows_updated": {
            "format": "int32",
            "type": "integer"
          },
          "source_note": {
            "type": [
              "string",
              "null"
            ]
          },
          "staged_chunks": {
            "description": "Async giant-batch bookkeeping (D2 remainder): staged chunk count and\nthe once-only worker-enqueue stamp.",
            "format": "int32",
            "type": "integer"
          },
          "started_at": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "label",
          "entity_kind",
          "conflict_policy",
          "dry_run",
          "rows_total",
          "rows_created",
          "rows_updated",
          "rows_skipped",
          "rows_failed",
          "started_at",
          "staged_chunks"
        ],
        "type": "object"
      },
      "BillingCandidateLine": {
        "description": "One draft invoice-line candidate. This is a PREVIEW shape: nothing\npersists until Wave 9's invoice run.",
        "properties": {
          "amount_minor": {
            "description": "Line total in minor units (currency on the parent evaluation).",
            "format": "int64",
            "type": "integer"
          },
          "client_id": {
            "format": "uuid",
            "type": "string"
          },
          "contract_id": {
            "format": "uuid",
            "type": "string"
          },
          "contract_number": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "kind": {
            "$ref": "#/components/schemas/BillingLineKind"
          },
          "period_end": {
            "format": "date",
            "type": "string"
          },
          "period_start": {
            "description": "The billing period (recurring/retainer) or the effective slice of\nthe evaluation window (T&M) or the fee's due date mirrored into\nboth ends (fixed fee). Inclusive start, exclusive end for\nperiod-derived lines.",
            "format": "date",
            "type": "string"
          },
          "quantity_minutes": {
            "description": "Labor minutes on the line (T&M/overage); 0 for amount lines.",
            "format": "int64",
            "type": "integer"
          },
          "unit_amount_minor": {
            "description": "Unit price in minor units: the hourly rate for labor lines, the\nfull amount otherwise.",
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "contract_id",
          "contract_number",
          "client_id",
          "kind",
          "period_start",
          "period_end",
          "description",
          "quantity_minutes",
          "unit_amount_minor",
          "amount_minor"
        ],
        "type": "object"
      },
      "BillingEvaluation": {
        "description": "The result of evaluating one contract's billing rules over a window.",
        "properties": {
          "client_id": {
            "format": "uuid",
            "type": "string"
          },
          "contract_id": {
            "format": "uuid",
            "type": "string"
          },
          "contract_number": {
            "type": "string"
          },
          "contract_type": {
            "$ref": "#/components/schemas/ContractType"
          },
          "currency": {
            "type": "string"
          },
          "from": {
            "description": "The evaluation window (inclusive bounds).",
            "format": "date",
            "type": "string"
          },
          "lines": {
            "items": {
              "$ref": "#/components/schemas/BillingCandidateLine"
            },
            "type": "array"
          },
          "to": {
            "format": "date",
            "type": "string"
          },
          "total_minor": {
            "description": "Sum of line amounts, minor units.",
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "contract_id",
          "contract_number",
          "client_id",
          "contract_type",
          "currency",
          "from",
          "to",
          "lines",
          "total_minor"
        ],
        "type": "object"
      },
      "BillingFrequency": {
        "description": "Billing period length. Period boundaries derive from the contract's\n`billing_anchor`: the anchor is the first period's start date and each\nsubsequent period starts one frequency step later (calendar-aware\nclamping lives in core-billing's period arithmetic).",
        "enum": [
          "weekly",
          "monthly",
          "quarterly",
          "semiannual",
          "annual"
        ],
        "type": "string"
      },
      "BillingLineKind": {
        "description": "Which billing rule produced a candidate line.",
        "enum": [
          "recurring_base",
          "retainer_base",
          "retainer_overage",
          "time_materials",
          "fixed_fee"
        ],
        "type": "string"
      },
      "BillingMethod": {
        "description": "How the project turns delivered work into money. The value rides the\nmilestone event payload so core-billing can route without re-reading the\nproject row (event payloads are additive-only, policy §2).",
        "enum": [
          "milestone",
          "time_and_materials",
          "fixed_fee",
          "non_billable"
        ],
        "type": "string"
      },
      "Board": {
        "properties": {
          "created_at": {
            "description": "Users whose favorite this board is (board groups/favorites, Stage 2).",
            "format": "date-time",
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "is_default": {
            "type": "boolean"
          },
          "name": {
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "require_checklist_close": {
            "description": "Pre-close checklist enforcement toggle (defaults OFF; closing is\ngated only when this AND a checklist template are both present —\ndefaults-first doctrine, migration 0016).",
            "type": "boolean"
          }
        },
        "required": [
          "id",
          "org_id",
          "name",
          "is_default",
          "require_checklist_close",
          "created_at"
        ],
        "type": "object"
      },
      "BoardExposureView": {
        "properties": {
          "board_id": {
            "format": "uuid",
            "type": "string"
          },
          "client_id": {
            "format": "uuid",
            "type": "string"
          },
          "exposed": {
            "type": "boolean"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "visible_status_ids": {
            "items": {
              "format": "uuid",
              "type": "string"
            },
            "type": "array"
          }
        },
        "required": [
          "id",
          "board_id",
          "client_id",
          "exposed",
          "visible_status_ids"
        ],
        "type": "object"
      },
      "BoardGroup": {
        "description": "A named, ordered nav grouping of boards within one org (TASKLIST 2.11).\nGroups are organization-wide; `owner_id` records who controls the group.",
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "owner_id": {
            "format": "uuid",
            "type": "string"
          },
          "position": {
            "format": "int32",
            "type": "integer"
          }
        },
        "required": [
          "id",
          "org_id",
          "owner_id",
          "name",
          "position",
          "created_at"
        ],
        "type": "object"
      },
      "BoardMember": {
        "description": "An explicit per-user membership on one board carrying a board-level\nrole tier (§6 board-level RBAC). Rows NARROW org grants; absence of a\nrow leaves org-level governance untouched.",
        "properties": {
          "board_id": {
            "format": "uuid",
            "type": "string"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "role": {
            "$ref": "#/components/schemas/BoardRole"
          },
          "user_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "org_id",
          "board_id",
          "user_id",
          "role",
          "created_at"
        ],
        "type": "object"
      },
      "BoardMemberView": {
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "display_name": {
            "type": "string"
          },
          "role": {
            "$ref": "#/components/schemas/BoardRole"
          },
          "user_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "user_id",
          "display_name",
          "role",
          "created_at"
        ],
        "type": "object"
      },
      "BoardNavEntry": {
        "description": "One left-nav entry: the board plus the CALLER's annotations.",
        "properties": {
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "favorite": {
            "description": "Whether THIS user favorited the board (star).",
            "type": "boolean"
          },
          "group_id": {
            "description": "Group assignment for the collapsible tree (`None` = ungrouped).",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "group_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "is_default": {
            "type": "boolean"
          },
          "my_role": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/BoardRole",
                "description": "The caller's board role (`None` = no membership row ⇒ org-governed)."
              }
            ]
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "name",
          "is_default",
          "favorite"
        ],
        "type": "object"
      },
      "BoardRole": {
        "description": "Per-board role tier stored on `board_members` rows (migration 0019,\nTASKLIST 2.11). Board roles sit BESIDE the org matrix and can only\nnarrow it — see `authorize_board_scoped`.",
        "enum": [
          "viewer",
          "member",
          "admin"
        ],
        "type": "string"
      },
      "BoardStatus": {
        "description": "A per-board status. `category` is the binding contract — labels are\npresentation, category is behavior.",
        "properties": {
          "board_id": {
            "format": "uuid",
            "type": "string"
          },
          "category": {
            "$ref": "#/components/schemas/TicketStatusCategory"
          },
          "color": {
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "is_entry": {
            "description": "Whether tickets may enter this status directly from New.",
            "type": "boolean"
          },
          "name": {
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "sort_order": {
            "format": "int32",
            "type": "integer"
          }
        },
        "required": [
          "id",
          "board_id",
          "org_id",
          "name",
          "category",
          "sort_order",
          "is_entry"
        ],
        "type": "object"
      },
      "BoardTransitionsResponse": {
        "description": "GET response for a board's workflow: either its explicit matrix or the\nmarker that the semantic-category floor governs.",
        "properties": {
          "edges": {
            "items": {
              "$ref": "#/components/schemas/TransitionEdge"
            },
            "type": "array"
          },
          "mode": {
            "description": "`\"explicit\"` when the listed edges are authoritative; `\"floor\"` when\nthe semantic-category default governs (any→any except closed→open).",
            "type": "string"
          }
        },
        "required": [
          "mode",
          "edges"
        ],
        "type": "object"
      },
      "BulkMoveRequest": {
        "properties": {
          "moves": {
            "items": {
              "$ref": "#/components/schemas/MoveSpec"
            },
            "type": "array"
          }
        },
        "required": [
          "moves"
        ],
        "type": "object"
      },
      "BulkMoveResponse": {
        "properties": {
          "moved": {
            "items": {
              "$ref": "#/components/schemas/DispatchAppointment"
            },
            "type": "array"
          }
        },
        "required": [
          "moved"
        ],
        "type": "object"
      },
      "BusinessCalendar": {
        "description": "Weekly business hours in a named IANA timezone, plus holiday dates.\n`None` window = non-business day.",
        "properties": {
          "holidays": {
            "description": "Local dates (YYYY-MM-DD) with no business hours.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "maintenance": {
            "description": "Downtime stretches subtracted from every measurement. Absent in\nlegacy documents (`default`) so stored policies keep deserializing.",
            "items": {
              "$ref": "#/components/schemas/MaintenanceWindow"
            },
            "type": "array"
          },
          "name": {
            "type": "string"
          },
          "timezone": {
            "type": "string"
          },
          "windows": {
            "description": "[Mon..Sun] open/close in local wall-clock \"HH:MM\".",
            "items": {
              "items": false,
              "prefixItems": [
                {
                  "type": "string"
                },
                {
                  "type": "string"
                }
              ],
              "type": [
                "array",
                "null"
              ]
            },
            "type": "array"
          }
        },
        "required": [
          "name",
          "timezone",
          "windows",
          "holidays"
        ],
        "type": "object"
      },
      "ByokOverviewResponse": {
        "description": "Summary of all configured AI providers for the org.",
        "properties": {
          "active_model": {
            "type": "string"
          },
          "active_provider": {
            "type": "string"
          },
          "configured_providers": {
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "required": [
          "active_provider",
          "active_model",
          "configured_providers"
        ],
        "type": "object"
      },
      "ByokSecretMutationResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ByokSecretStatus"
          },
          {
            "properties": {
              "mutation": {
                "$ref": "#/components/schemas/MutationMeta"
              }
            },
            "required": [
              "mutation"
            ],
            "type": "object"
          }
        ],
        "description": "Mutation response: status fields plus the instant-first mutation\nmetadata (`mutation.version` echoes into the next write)."
      },
      "ByokSecretStatus": {
        "description": "Non-secret status of a stored BYOK key (presence flags only — never\nkey material). Flattened into mutation responses so a stored replay\ndeserializes byte-identically.",
        "properties": {
          "has_key": {
            "type": "boolean"
          },
          "provider": {
            "type": "string"
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "provider",
          "has_key",
          "updated_at"
        ],
        "type": "object"
      },
      "CalendarExclusion": {
        "description": "Absolute UTC time-off punching holes in availability.",
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "ends_at": {
            "format": "date-time",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "starts_at": {
            "format": "date-time",
            "type": "string"
          },
          "user_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "user_id",
          "starts_at",
          "ends_at",
          "created_at"
        ],
        "type": "object"
      },
      "CalendarItem": {
        "description": "Flat merged entry so calendars render one ordered list without caring\nwhich table produced it.",
        "properties": {
          "category": {
            "description": "On-call-only field.",
            "type": [
              "string",
              "null"
            ]
          },
          "ends_at": {
            "format": "date-time",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "item_type": {
            "description": "\"appointment\" | \"on_call\"",
            "type": "string"
          },
          "kind": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/AppointmentKind",
                "description": "Appointment-only fields."
              }
            ]
          },
          "starts_at": {
            "format": "date-time",
            "type": "string"
          },
          "status": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/AppointmentStatus"
              }
            ]
          },
          "ticket_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "title": {
            "type": [
              "string",
              "null"
            ]
          },
          "user_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "item_type",
          "id",
          "user_id",
          "starts_at",
          "ends_at"
        ],
        "type": "object"
      },
      "CalendarViewResponse": {
        "properties": {
          "availability_windows": {
            "description": "Present on personal views only (templates are per-user).",
            "items": {
              "$ref": "#/components/schemas/AvailabilityWindow"
            },
            "type": "array"
          },
          "exclusions": {
            "items": {
              "$ref": "#/components/schemas/CalendarExclusion"
            },
            "type": "array"
          },
          "from": {
            "format": "date-time",
            "type": "string"
          },
          "items": {
            "description": "Merged appointments + on-call, ordered by starts_at then id.",
            "items": {
              "$ref": "#/components/schemas/CalendarItem"
            },
            "type": "array"
          },
          "timezone": {
            "type": "string"
          },
          "to": {
            "format": "date-time",
            "type": "string"
          },
          "user_id": {
            "description": "None on team-wide views.",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "from",
          "to",
          "timezone",
          "items",
          "exclusions",
          "availability_windows"
        ],
        "type": "object"
      },
      "CapabilityGrantList": {
        "properties": {
          "grants": {
            "items": {
              "$ref": "#/components/schemas/CapabilityGrantView"
            },
            "type": "array"
          }
        },
        "required": [
          "grants"
        ],
        "type": "object"
      },
      "CapabilityGrantView": {
        "description": "One granted capability with its dial position.",
        "properties": {
          "capability": {
            "type": "string"
          },
          "granted_at": {
            "type": "string"
          },
          "granted_by": {
            "format": "uuid",
            "type": "string"
          },
          "mode": {
            "$ref": "#/components/schemas/CapabilityMode"
          },
          "updated_at": {
            "type": "string"
          }
        },
        "required": [
          "capability",
          "mode",
          "granted_by",
          "granted_at",
          "updated_at"
        ],
        "type": "object"
      },
      "CapabilityMode": {
        "description": "Wire involvement-dial position of a capability grant.",
        "enum": [
          "proposed",
          "autonomous"
        ],
        "type": "string"
      },
      "CapacityHorizonView": {
        "description": "The assembled horizon payload. `unassigned_count` is the current open\nunassigned queue depth so planners see demand next to capacity.",
        "properties": {
          "days": {
            "format": "int32",
            "minimum": 0,
            "type": "integer"
          },
          "from": {
            "format": "date",
            "type": "string"
          },
          "technicians": {
            "items": {
              "$ref": "#/components/schemas/TechnicianCapacity"
            },
            "type": "array"
          },
          "unassigned_count": {
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "from",
          "days",
          "technicians",
          "unassigned_count"
        ],
        "type": "object"
      },
      "CapacityQuery": {
        "description": "GET /api/dispatch/capacity query: `from` date (defaults to today UTC)\nand the horizon length in days (1..=31, default 7).",
        "properties": {
          "days": {
            "description": "Horizon length in days (1..=31).",
            "format": "int32",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          },
          "from": {
            "format": "date",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "CategoryMutationResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/KbCategory"
          },
          {
            "properties": {
              "mutation": {
                "$ref": "#/components/schemas/MutationMeta"
              }
            },
            "required": [
              "mutation"
            ],
            "type": "object"
          }
        ],
        "description": "Instant-first mutation response (IF2): category fields at the top level\nplus the additive `mutation` metadata."
      },
      "ChangeStatusRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1): idempotency key + entity\nversion. Absent in legacy clients — purely additive."
          },
          {
            "properties": {
              "status_id": {
                "format": "uuid",
                "type": "string"
              }
            },
            "required": [
              "status_id"
            ],
            "type": "object"
          }
        ]
      },
      "ChecklistItem": {
        "description": "One line of a ticket's pre-close checklist. Items instantiated from the\nboard's template carry `template_item_id`; those are REQUIRED when the\nboard enforces pre-close checklists (see `crate::notes`). Ad-hoc items\n(`template_item_id == None`) never block closure.",
        "properties": {
          "checked": {
            "type": "boolean"
          },
          "checked_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "checked_by": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "sort_order": {
            "format": "int32",
            "type": "integer"
          },
          "template_item_id": {
            "description": "Template provenance: `Some` ⇒ required under enforcement.",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "text": {
            "type": "string"
          },
          "ticket_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "ticket_id",
          "text",
          "checked",
          "sort_order"
        ],
        "type": "object"
      },
      "ChecklistProgress": {
        "description": "Derived-at-read-time checklist progress (never materialized — see the\n0016 migration header for the justification). `required_open` counts\nunchecked template-derived instances: the close-blocking set when the\nboard enforces.",
        "properties": {
          "checked": {
            "description": "Checked rows across both classes.",
            "format": "int64",
            "type": "integer"
          },
          "required_open": {
            "description": "Unchecked REQUIRED (template-derived) rows.",
            "format": "int64",
            "type": "integer"
          },
          "total": {
            "description": "All instance rows (template-derived + ad-hoc).",
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "total",
          "checked",
          "required_open"
        ],
        "type": "object"
      },
      "ChecklistTemplate": {
        "description": "A board's pre-close checklist template. Exactly one per board\n(UNIQUE in storage): the deterministic gate consulted at close time.",
        "properties": {
          "board_id": {
            "format": "uuid",
            "type": "string"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "board_id",
          "name",
          "created_at",
          "updated_at"
        ],
        "type": "object"
      },
      "ChecklistTemplateItem": {
        "description": "One required step in a template. Instances on tickets link back to this\nid (`checklist_items.template_item_id`), so enforcement follows identity,\nnever fragile text matching.",
        "properties": {
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "sort_order": {
            "format": "int32",
            "type": "integer"
          },
          "template_id": {
            "format": "uuid",
            "type": "string"
          },
          "text": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "template_id",
          "text",
          "sort_order"
        ],
        "type": "object"
      },
      "ChecklistTemplateView": {
        "description": "GET /api/boards/{id}/checklist-template response: the template (if any),\nits items, and the enforcement posture actually applied at close time.",
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/ChecklistTemplateItem"
            },
            "type": "array"
          },
          "require_checklist_close": {
            "description": "Mirrors `boards.require_checklist_close`.",
            "type": "boolean"
          },
          "template": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ChecklistTemplate"
              }
            ]
          }
        },
        "required": [
          "items",
          "require_checklist_close"
        ],
        "type": "object"
      },
      "ChunkRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/RowsPayload"
          },
          {
            "properties": {
              "template_id": {
                "description": "Optional saved field-mapping template applied before validation.",
                "format": "uuid",
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "type": "object"
          }
        ],
        "description": "POST /imports/batches/{id}/chunks request body."
      },
      "ChunkSummaryWire": {
        "description": "u32-friendly mirror of [`core_domain::import_core::ChunkSummary`] so the\ngenerated SDK gets plain integers without overflow caveats.",
        "properties": {
          "failed": {
            "format": "int32",
            "minimum": 0,
            "type": "integer"
          },
          "ok": {
            "format": "int32",
            "minimum": 0,
            "type": "integer"
          },
          "total": {
            "format": "int32",
            "minimum": 0,
            "type": "integer"
          },
          "would_skip": {
            "format": "int32",
            "minimum": 0,
            "type": "integer"
          },
          "would_update": {
            "format": "int32",
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "total",
          "ok",
          "would_update",
          "would_skip",
          "failed"
        ],
        "type": "object"
      },
      "Client": {
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "restricted_to": {
            "description": "Optional per-client visibility: when set, only these users (plus\nadmins) can see the client. Empty = all org members.",
            "items": {
              "format": "uuid",
              "type": "string"
            },
            "type": "array"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "name",
          "restricted_to",
          "created_at",
          "updated_at"
        ],
        "type": "object"
      },
      "ClientMutationResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Client"
          },
          {
            "properties": {
              "mutation": {
                "$ref": "#/components/schemas/MutationMeta"
              }
            },
            "required": [
              "mutation"
            ],
            "type": "object"
          }
        ],
        "description": "Instant-first mutation response (IF2): client fields at the top level\n(unchanged shape) plus the additive `mutation` metadata."
      },
      "CommentListQuery": {
        "properties": {
          "kind": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/NoteKind",
                "description": "Optional taxonomy filter (`internal`, `client_visible`,\n`in_house_update`). Omit for all kinds (staff view)."
              }
            ]
          }
        },
        "type": "object"
      },
      "CommittedChunkRef": {
        "description": "One committed chunk's position in the resume view.",
        "properties": {
          "chunk_index": {
            "format": "int64",
            "type": "integer"
          },
          "committed_at": {
            "type": "string"
          }
        },
        "required": [
          "chunk_index",
          "committed_at"
        ],
        "type": "object"
      },
      "ConflictCheckRequest": {
        "properties": {
          "ends_at": {
            "format": "date-time",
            "type": "string"
          },
          "exclude_appointment_id": {
            "description": "Appointment excluded from the check (its own id when rescheduling).",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "starts_at": {
            "format": "date-time",
            "type": "string"
          },
          "user_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "user_id",
          "starts_at",
          "ends_at"
        ],
        "type": "object"
      },
      "ConflictCheckResponse": {
        "properties": {
          "conflicts": {
            "items": {
              "$ref": "#/components/schemas/ConflictView"
            },
            "type": "array"
          },
          "has_conflict": {
            "type": "boolean"
          }
        },
        "required": [
          "has_conflict",
          "conflicts"
        ],
        "type": "object"
      },
      "ConflictPolicy": {
        "description": "Per-entity conflict semantics when an external key already maps to a\nlive row whose content differs from the incoming spec.",
        "enum": [
          "skip",
          "update",
          "fail"
        ],
        "type": "string"
      },
      "ConflictView": {
        "description": "One blocking booking named by the dry-run.",
        "properties": {
          "appointment_id": {
            "format": "uuid",
            "type": "string"
          },
          "ends_at": {
            "format": "date-time",
            "type": "string"
          },
          "starts_at": {
            "format": "date-time",
            "type": "string"
          },
          "title": {
            "type": "string"
          }
        },
        "required": [
          "appointment_id",
          "title",
          "starts_at",
          "ends_at"
        ],
        "type": "object"
      },
      "ConnectorAppointment": {
        "description": "One booking as the connector sees it.",
        "properties": {
          "client_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "client_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "dispatch_status": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ConnectorStatusView",
                "description": "Latest pushed field-service status, when any."
              }
            ]
          },
          "ends_at": {
            "format": "date-time",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "kind": {
            "type": "string"
          },
          "starts_at": {
            "format": "date-time",
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "technician_name": {
            "type": "string"
          },
          "technician_user_id": {
            "format": "uuid",
            "type": "string"
          },
          "ticket_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "ticket_number": {
            "type": [
              "string",
              "null"
            ]
          },
          "title": {
            "type": "string"
          },
          "travel_minutes": {
            "format": "int32",
            "type": "integer"
          }
        },
        "required": [
          "id",
          "technician_user_id",
          "technician_name",
          "title",
          "starts_at",
          "ends_at",
          "kind",
          "status",
          "travel_minutes"
        ],
        "type": "object"
      },
      "ConnectorScheduleQuery": {
        "description": "GET /api/dispatch-connector/schedule query. The window is bounded at\n62 days so one pull cannot scan the whole calendar.",
        "properties": {
          "days": {
            "description": "Window length in days (1..=62, default 7).",
            "format": "int32",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          },
          "from": {
            "format": "date",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "ConnectorScheduleView": {
        "properties": {
          "appointments": {
            "items": {
              "$ref": "#/components/schemas/ConnectorAppointment"
            },
            "type": "array"
          },
          "days": {
            "format": "int32",
            "minimum": 0,
            "type": "integer"
          },
          "from": {
            "format": "date",
            "type": "string"
          }
        },
        "required": [
          "from",
          "days",
          "appointments"
        ],
        "type": "object"
      },
      "ConnectorStatusView": {
        "description": "The latest status push for one booking.",
        "properties": {
          "note": {
            "type": [
              "string",
              "null"
            ]
          },
          "occurred_at": {
            "format": "date-time",
            "type": "string"
          },
          "source": {
            "description": "`connector` | `staff`.",
            "type": "string"
          },
          "status": {
            "type": "string"
          }
        },
        "required": [
          "status",
          "source",
          "occurred_at"
        ],
        "type": "object"
      },
      "ConnectorTechnician": {
        "description": "GET /api/dispatch-connector/technicians entry.",
        "properties": {
          "display_name": {
            "type": "string"
          },
          "skills": {
            "description": "Current (non-expired) skills — lets the external planner respect\ncertifications before proposing a dispatch.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "user_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "user_id",
          "display_name",
          "skills"
        ],
        "type": "object"
      },
      "ConnectorTechniciansView": {
        "properties": {
          "technicians": {
            "items": {
              "$ref": "#/components/schemas/ConnectorTechnician"
            },
            "type": "array"
          }
        },
        "required": [
          "technicians"
        ],
        "type": "object"
      },
      "Contact": {
        "properties": {
          "client_id": {
            "format": "uuid",
            "type": "string"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "email": {
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "is_primary": {
            "type": "boolean"
          },
          "name": {
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "phone": {
            "type": [
              "string",
              "null"
            ]
          },
          "site_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "title": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "org_id",
          "client_id",
          "name",
          "is_primary",
          "created_at"
        ],
        "type": "object"
      },
      "Contract": {
        "description": "A commercial agreement with one client. Money fields are integer minor\nunits (cents for USD) — floats are forbidden near amounts (§5).",
        "properties": {
          "amount_minor": {
            "description": "Per-period price (recurring/retainer), minor units.",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "billing_anchor": {
            "description": "Required for recurring/retainer; the first billing period's start.",
            "format": "date",
            "type": [
              "string",
              "null"
            ]
          },
          "billing_frequency": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/BillingFrequency",
                "description": "Required for recurring/retainer; the period cadence."
              }
            ]
          },
          "client_id": {
            "format": "uuid",
            "type": "string"
          },
          "contract_type": {
            "$ref": "#/components/schemas/ContractType"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "currency": {
            "description": "ISO 4217 code; every amount on the contract uses this currency.",
            "type": "string"
          },
          "effective_from": {
            "description": "First day the agreement can generate billable candidates.",
            "format": "date",
            "type": "string"
          },
          "effective_until": {
            "description": "Last day it can; `None` = open-ended.",
            "format": "date",
            "type": [
              "string",
              "null"
            ]
          },
          "hourly_rate_minor": {
            "description": "Default hourly rate for T&M when no rate card row matches the\nentry's `work_type`, minor units per hour.",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "included_minutes": {
            "description": "Retainer: labor minutes included in each period's base price.",
            "format": "int32",
            "type": [
              "integer",
              "null"
            ]
          },
          "name": {
            "type": "string"
          },
          "notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "number": {
            "description": "Human contract number, unique per org (e.g. \"C-2026-014\").",
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "overage_rate_minor": {
            "description": "Retainer: hourly rate for minutes beyond the included block.",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "status": {
            "$ref": "#/components/schemas/ContractStatus"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "client_id",
          "number",
          "name",
          "contract_type",
          "status",
          "currency",
          "effective_from",
          "created_at",
          "updated_at"
        ],
        "type": "object"
      },
      "ContractDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Contract"
          },
          {
            "properties": {
              "fees": {
                "items": {
                  "$ref": "#/components/schemas/ContractFixedFee"
                },
                "type": "array"
              },
              "rates": {
                "items": {
                  "$ref": "#/components/schemas/ContractRate"
                },
                "type": "array"
              }
            },
            "required": [
              "rates",
              "fees"
            ],
            "type": "object"
          }
        ],
        "description": "The contract aggregate as one view: the agreement plus its rate card\nand fee schedule."
      },
      "ContractFixedFee": {
        "description": "Fixed-fee schedule entry: becomes a candidate line when `due_on` falls\ninside the evaluation window (and the effective window).",
        "properties": {
          "amount_minor": {
            "format": "int64",
            "type": "integer"
          },
          "contract_id": {
            "format": "uuid",
            "type": "string"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "due_on": {
            "format": "date",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "contract_id",
          "label",
          "amount_minor",
          "due_on",
          "created_at"
        ],
        "type": "object"
      },
      "ContractListQuery": {
        "properties": {
          "client_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "effective_on": {
            "description": "Only contracts effective on this date.",
            "format": "date",
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "description": "Exact status: `draft|active|ended|cancelled`.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "ContractMutationResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ContractDetail"
          },
          {
            "properties": {
              "mutation": {
                "$ref": "#/components/schemas/MutationMeta"
              }
            },
            "required": [
              "mutation"
            ],
            "type": "object"
          }
        ],
        "description": "Instant-first mutation response (IF2): contract aggregate at the top\nlevel plus the additive `mutation` metadata."
      },
      "ContractRate": {
        "description": "T&M rate card row: the hourly rate for time entries whose `work_type`\nmatches `work_type`. Entries with no matching row bill at the\ncontract's default `hourly_rate_minor`.",
        "properties": {
          "contract_id": {
            "format": "uuid",
            "type": "string"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "rate_minor": {
            "description": "Hourly rate in minor units.",
            "format": "int64",
            "type": "integer"
          },
          "work_type": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "contract_id",
          "work_type",
          "rate_minor",
          "created_at"
        ],
        "type": "object"
      },
      "ContractStatus": {
        "description": "Lifecycle. `draft` contracts evaluate in previews (plan before\nactivation) but Wave 9's invoice runs will refuse them; `cancelled`\ncontracts never evaluate. `ended` keeps evaluating candidates whose\ndates fall inside the (closed) effective window.",
        "enum": [
          "draft",
          "active",
          "ended",
          "cancelled"
        ],
        "type": "string"
      },
      "ContractType": {
        "description": "The four supported commercial agreement shapes.",
        "enum": [
          "recurring",
          "time_and_materials",
          "retainer",
          "fixed_fee"
        ],
        "type": "string"
      },
      "CreateAlertSourceRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1) — idempotency key."
          },
          {
            "properties": {
              "board_id": {
                "description": "Board incident tickets land on.",
                "format": "uuid",
                "type": "string"
              },
              "client_id": {
                "description": "Optional client context stamped onto created incident tickets.",
                "format": "uuid",
                "type": [
                  "string",
                  "null"
                ]
              },
              "correlation_window_secs": {
                "description": "Storm window in seconds (10..=86400; default 900).",
                "format": "int32",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "name": {
                "type": "string"
              },
              "source_ref": {
                "description": "Optional custom routing id (3–64 chars of `[a-z0-9-]`); generated\nwhen absent. Globally unique — collisions are a typed 409.",
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "name",
              "board_id"
            ],
            "type": "object"
          }
        ]
      },
      "CreateApiKeyRequest": {
        "properties": {
          "name": {
            "type": "string"
          },
          "scopes": {
            "description": "Capability scopes from [`KNOWN_SCOPES`].",
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "required": [
          "name",
          "scopes"
        ],
        "type": "object"
      },
      "CreateAppointmentRequest": {
        "properties": {
          "client_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "ends_at": {
            "format": "date-time",
            "type": "string"
          },
          "kind": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/AppointmentKind",
                "description": "Defaults to on_site when omitted."
              }
            ]
          },
          "notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "site_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "starts_at": {
            "format": "date-time",
            "type": "string"
          },
          "ticket_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "title": {
            "type": "string"
          },
          "travel_minutes": {
            "description": "Dispatch placeholder, stored verbatim (RoutingProvider comes later).",
            "format": "int32",
            "type": "integer"
          },
          "user_id": {
            "description": "Assignee whose calendar holds the slot. Defaults to the caller;\nbooking for someone else requires owner/admin.",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "title",
          "starts_at",
          "ends_at"
        ],
        "type": "object"
      },
      "CreateArticleRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1)."
          },
          {
            "properties": {
              "body": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "category_id": {
                "format": "uuid",
                "type": [
                  "string",
                  "null"
                ]
              },
              "client_visible": {
                "description": "Portal v2 gate: effective client visibility additionally requires a\npublished status and a client-visible category (core_kb rule).",
                "type": "boolean"
              },
              "slug": {
                "description": "Stable per-org handle; derived from the title when omitted.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "status": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/KbArticleStatus"
                  }
                ]
              },
              "title": {
                "type": "string"
              }
            },
            "required": [
              "title"
            ],
            "type": "object"
          }
        ]
      },
      "CreateAssetRequest": {
        "properties": {
          "kind": {
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "type": "string"
          },
          "tag": {
            "type": "string"
          }
        },
        "required": [
          "tag",
          "name"
        ],
        "type": "object"
      },
      "CreateAvailabilityRequest": {
        "properties": {
          "effective_from": {
            "type": [
              "string",
              "null"
            ]
          },
          "effective_until": {
            "type": [
              "string",
              "null"
            ]
          },
          "end_local": {
            "type": "string"
          },
          "start_local": {
            "description": "Local wall-clock \"HH:MM\" (window is `[start, end)`).",
            "type": "string"
          },
          "timezone": {
            "description": "IANA timezone the wall-clock bounds live in.",
            "type": "string"
          },
          "user_id": {
            "description": "Whose calendar. Defaults to the caller; another user requires\nowner/admin.",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "weekday": {
            "description": "0 = Monday … 6 = Sunday.",
            "format": "int32",
            "type": "integer"
          }
        },
        "required": [
          "weekday",
          "start_local",
          "end_local",
          "timezone"
        ],
        "type": "object"
      },
      "CreateBatchRequest": {
        "description": "POST /api/imports/batches — opens a committed-run span. Chunks then land\nthrough `/chunks` (synchronous) or `/stage` + `/run` (async, D2\nremainder) until the batch finishes.",
        "properties": {
          "conflict_policy": {
            "$ref": "#/components/schemas/ConflictPolicy"
          },
          "entity_kind": {
            "$ref": "#/components/schemas/EntityKind"
          },
          "label": {
            "type": [
              "string",
              "null"
            ]
          },
          "source_note": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "entity_kind",
          "conflict_policy"
        ],
        "type": "object"
      },
      "CreateBoardRequest": {
        "properties": {
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "is_default": {
            "type": "boolean"
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "name",
          "is_default"
        ],
        "type": "object"
      },
      "CreateCalendarRequest": {
        "properties": {
          "calendar": {
            "$ref": "#/components/schemas/BusinessCalendar",
            "description": "Timezone/windows/holidays/maintenance document."
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "name",
          "calendar"
        ],
        "type": "object"
      },
      "CreateCategoryRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1)."
          },
          {
            "properties": {
              "client_visible": {
                "description": "Portal v2 gate: only categories with this flag can expose articles\nto client users.",
                "type": "boolean"
              },
              "description": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "name": {
                "type": "string"
              },
              "position": {
                "format": "int32",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "slug": {
                "description": "Stable per-org handle; derived from the name when omitted.",
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "name"
            ],
            "type": "object"
          }
        ]
      },
      "CreateClientRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1): idempotency key. Absent in\nlegacy clients — purely additive. (Creates carry no version.)"
          },
          {
            "properties": {
              "name": {
                "type": "string"
              },
              "notes": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "name"
            ],
            "type": "object"
          }
        ]
      },
      "CreateContactRequest": {
        "properties": {
          "email": {
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "type": "string"
          },
          "phone": {
            "type": [
              "string",
              "null"
            ]
          },
          "title": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "name"
        ],
        "type": "object"
      },
      "CreateContractRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1): idempotency key. Absent\nin legacy clients — purely additive. (Creates carry no version.)"
          },
          {
            "properties": {
              "amount_minor": {
                "description": "Per-period price (recurring/retainer), minor units.",
                "format": "int64",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "billing_anchor": {
                "description": "Required for recurring/retainer; first billing period's start.",
                "format": "date",
                "type": [
                  "string",
                  "null"
                ]
              },
              "billing_frequency": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/BillingFrequency",
                    "description": "Required for recurring/retainer."
                  }
                ]
              },
              "client_id": {
                "format": "uuid",
                "type": "string"
              },
              "contract_type": {
                "$ref": "#/components/schemas/ContractType"
              },
              "currency": {
                "description": "ISO 4217 code (e.g. \"USD\"); every amount uses this currency.",
                "type": "string"
              },
              "effective_from": {
                "format": "date",
                "type": "string"
              },
              "effective_until": {
                "format": "date",
                "type": [
                  "string",
                  "null"
                ]
              },
              "fees": {
                "description": "Fee schedule (only valid on fixed_fee contracts).",
                "items": {
                  "$ref": "#/components/schemas/FeeSpec"
                },
                "type": "array"
              },
              "hourly_rate_minor": {
                "description": "T&M default hourly rate, minor units.",
                "format": "int64",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "included_minutes": {
                "description": "Retainer included minutes per period.",
                "format": "int32",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "name": {
                "type": "string"
              },
              "notes": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "number": {
                "type": "string"
              },
              "overage_rate_minor": {
                "description": "Retainer hourly overage rate, minor units.",
                "format": "int64",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "rates": {
                "description": "T&M rate card (only valid on time_and_materials contracts).",
                "items": {
                  "$ref": "#/components/schemas/RateSpec"
                },
                "type": "array"
              },
              "status": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/ContractStatus",
                    "description": "Defaults to `draft`."
                  }
                ]
              }
            },
            "required": [
              "client_id",
              "number",
              "name",
              "contract_type",
              "currency",
              "effective_from"
            ],
            "type": "object"
          }
        ]
      },
      "CreateDocumentRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1)."
          },
          {
            "properties": {
              "body": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "change_summary": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "title": {
                "type": "string"
              }
            },
            "required": [
              "title"
            ],
            "type": "object"
          }
        ]
      },
      "CreateExclusionRequest": {
        "properties": {
          "ends_at": {
            "format": "date-time",
            "type": "string"
          },
          "reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "starts_at": {
            "format": "date-time",
            "type": "string"
          },
          "user_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "starts_at",
          "ends_at"
        ],
        "type": "object"
      },
      "CreateFieldDefRequest": {
        "properties": {
          "kind": {
            "$ref": "#/components/schemas/FieldKindWire"
          },
          "name": {
            "type": "string"
          },
          "options": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "required": {
            "type": "boolean"
          },
          "sort_order": {
            "format": "int32",
            "type": "integer"
          }
        },
        "required": [
          "name",
          "kind"
        ],
        "type": "object"
      },
      "CreateGroupRequest": {
        "properties": {
          "name": {
            "type": "string"
          },
          "position": {
            "format": "int32",
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "required": [
          "name"
        ],
        "type": "object"
      },
      "CreateInvoiceRunRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1): idempotency key."
          },
          {
            "properties": {
              "client_id": {
                "description": "Restrict the run to one client's billable contracts.",
                "format": "uuid",
                "type": [
                  "string",
                  "null"
                ]
              },
              "due_in_days": {
                "description": "Payment terms for the issued invoices, in days (default 30).",
                "format": "int32",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "from": {
                "description": "Window start (inclusive), ISO date.",
                "format": "date",
                "type": "string"
              },
              "to": {
                "description": "Window end (inclusive), ISO date.",
                "format": "date",
                "type": "string"
              }
            },
            "required": [
              "from",
              "to"
            ],
            "type": "object"
          }
        ]
      },
      "CreateOnCallRequest": {
        "properties": {
          "category": {
            "description": "Rotation label ('primary', 'secondary', 'escalation', …).",
            "type": "string"
          },
          "ends_at": {
            "format": "date-time",
            "type": "string"
          },
          "notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "starts_at": {
            "format": "date-time",
            "type": "string"
          },
          "user_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "starts_at",
          "ends_at",
          "category"
        ],
        "type": "object"
      },
      "CreatePhaseRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1): idempotency key + entity\nversion. Absent in legacy clients — purely additive."
          },
          {
            "properties": {
              "description": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "is_milestone": {
                "type": "boolean"
              },
              "milestone_amount_minor": {
                "format": "int64",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "milestone_currency": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "name": {
                "type": "string"
              },
              "sort_order": {
                "format": "int32",
                "type": "integer"
              }
            },
            "required": [
              "name"
            ],
            "type": "object"
          }
        ]
      },
      "CreatePortalUserRequest": {
        "properties": {
          "display_name": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "password": {
            "description": "Initial credential, hashed with argon2id before storage. The admin\ndelivers it to the contact out-of-band (v1 has no invite email).",
            "type": "string"
          },
          "role": {
            "$ref": "#/components/schemas/PortalRole"
          }
        },
        "required": [
          "email",
          "display_name",
          "password",
          "role"
        ],
        "type": "object"
      },
      "CreateProjectRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1): idempotency key + entity\nversion. Absent in legacy clients — purely additive."
          },
          {
            "properties": {
              "billing_method": {
                "$ref": "#/components/schemas/BillingMethod"
              },
              "budget_minor": {
                "format": "int64",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "client_id": {
                "format": "uuid",
                "type": [
                  "string",
                  "null"
                ]
              },
              "currency": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "description": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "due_date": {
                "format": "date",
                "type": [
                  "string",
                  "null"
                ]
              },
              "name": {
                "type": "string"
              },
              "start_date": {
                "format": "date",
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "name"
            ],
            "type": "object"
          }
        ]
      },
      "CreateProposalRequest": {
        "description": "POST /api/agent-proposals body.",
        "properties": {
          "agent_ref": {
            "description": "Agent provenance (§5). Optional: the machine identity defaults to\nthe caller's (`api-key:<id>` / `user:<id>`).",
            "type": [
              "string",
              "null"
            ]
          },
          "before_value": {
            "description": "The value the agent saw when it drafted the change (the IF8\nbefore-snapshot). `null` for creates. Application re-reads the\nlive entity, so this is decision context, not a blind write.",
            "type": [
              "object",
              "null"
            ]
          },
          "capability": {
            "description": "Write capability this change belongs to (must be granted).",
            "type": [
              "string",
              "null"
            ]
          },
          "classification": {
            "$ref": "#/components/schemas/ProposalClassification"
          },
          "entity": {
            "type": "string"
          },
          "entity_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "for_user": {
            "description": "The user the agent acted on behalf of.",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "op": {
            "type": "string"
          },
          "proposed_value": {
            "type": "object"
          },
          "rationale": {
            "type": [
              "string",
              "null"
            ]
          },
          "rule_set_hash": {
            "description": "Hash of the evaluated rule set at proposal time.",
            "type": [
              "string",
              "null"
            ]
          },
          "session_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "skill_slug": {
            "type": [
              "string",
              "null"
            ]
          },
          "skill_version": {
            "format": "int32",
            "type": [
              "integer",
              "null"
            ]
          },
          "tool": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "entity",
          "op",
          "proposed_value"
        ],
        "type": "object"
      },
      "CreateProposalResponse": {
        "description": "POST /api/agent-proposals response: the stored proposal.",
        "properties": {
          "proposal": {
            "$ref": "#/components/schemas/AgentProposalView"
          }
        },
        "required": [
          "proposal"
        ],
        "type": "object"
      },
      "CreatePushSessionRequest": {
        "description": "POST /api/migration/push/sessions body.",
        "properties": {
          "conflict_policy": {
            "$ref": "#/components/schemas/ConflictPolicy"
          },
          "entity_kind": {
            "$ref": "#/components/schemas/EntityKind"
          },
          "label": {
            "description": "Operator-facing run label.",
            "type": [
              "string",
              "null"
            ]
          },
          "source_note": {
            "description": "Free-form note about the third-party source system.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "entity_kind",
          "conflict_policy"
        ],
        "type": "object"
      },
      "CreateReportDefinitionRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams"
          },
          {
            "properties": {
              "description": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "name": {
                "description": "Org-unique display name (1–200 chars after trimming).",
                "type": "string"
              },
              "scope": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/DefinitionScope",
                    "description": "Requested visibility; `org` requires admin and non-admins are\nforced onto `self` regardless."
                  }
                ]
              },
              "spec": {
                "$ref": "#/components/schemas/ReportSpec",
                "description": "The registry-validated report spec."
              }
            },
            "required": [
              "name",
              "spec"
            ],
            "type": "object"
          }
        ],
        "description": "POST /api/report-definitions body."
      },
      "CreateReportScheduleRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams"
          },
          {
            "properties": {
              "cadence": {
                "$ref": "#/components/schemas/ScheduleCadence"
              },
              "day_of_month": {
                "description": "Monthly only: 1..=28.",
                "format": "int32",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "day_of_week": {
                "description": "Weekly only: 0 = Monday .. 6 = Sunday.",
                "format": "int32",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "enabled": {
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "name": {
                "description": "Org-unique display name (1–200 chars after trimming).",
                "type": "string"
              },
              "recipients": {
                "description": "Recipient staff users of this org (1–50).",
                "items": {
                  "format": "uuid",
                  "type": "string"
                },
                "type": "array"
              },
              "report_definition_id": {
                "description": "The stored R3 definition this schedule delivers.",
                "format": "uuid",
                "type": "string"
              },
              "time_of_day": {
                "description": "`HH:MM` or `HH:MM:SS`, read in `timezone`.",
                "type": "string"
              },
              "timezone": {
                "description": "IANA zone the wall clock reads in.",
                "type": "string"
              },
              "window_days": {
                "description": "Trailing-day window per run (1..=366); default 30.",
                "format": "int32",
                "type": [
                  "integer",
                  "null"
                ]
              }
            },
            "required": [
              "name",
              "report_definition_id",
              "recipients",
              "cadence",
              "time_of_day",
              "timezone"
            ],
            "type": "object"
          }
        ],
        "description": "POST /api/report-schedules body."
      },
      "CreateRuleRequest": {
        "properties": {
          "actions": {
            "description": "Action documents (see AutomationAction schema)."
          },
          "board_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "conditions": {
            "description": "Condition documents (see AutomationCondition schema)."
          },
          "name": {
            "type": "string"
          },
          "trigger_event": {
            "description": "Domain event type, e.g. \"ticket.created\".",
            "type": "string"
          }
        },
        "required": [
          "name",
          "trigger_event",
          "conditions",
          "actions"
        ],
        "type": "object"
      },
      "CreateSiteRequest": {
        "properties": {
          "address": {
            "type": [
              "string",
              "null"
            ]
          },
          "city": {
            "type": [
              "string",
              "null"
            ]
          },
          "country": {
            "type": [
              "string",
              "null"
            ]
          },
          "latitude": {
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          },
          "longitude": {
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          },
          "name": {
            "type": "string"
          },
          "postal_code": {
            "type": [
              "string",
              "null"
            ]
          },
          "region": {
            "type": [
              "string",
              "null"
            ]
          },
          "timezone": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "name"
        ],
        "type": "object"
      },
      "CreateStatusRequest": {
        "properties": {
          "category": {
            "$ref": "#/components/schemas/TicketStatusCategory",
            "description": "The semantic category this status binds to — behavior (SLA pauses,\nbilling, automations) reads the category, never the label (§5)."
          },
          "is_entry": {
            "type": "boolean"
          },
          "name": {
            "type": "string"
          },
          "sort_order": {
            "format": "int32",
            "type": "integer"
          }
        },
        "required": [
          "name",
          "category",
          "sort_order",
          "is_entry"
        ],
        "type": "object"
      },
      "CreateTaskRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1): idempotency key + entity\nversion. Absent in legacy clients — purely additive."
          },
          {
            "properties": {
              "assignee_id": {
                "format": "uuid",
                "type": [
                  "string",
                  "null"
                ]
              },
              "depends_on": {
                "description": "Finish-to-start dependencies to create with the task; every id must\nbe a task of the SAME project. Cycles are impossible at creation\n(nothing can depend on the not-yet-existing task) but membership is\nvalidated.",
                "items": {
                  "format": "uuid",
                  "type": "string"
                },
                "type": "array"
              },
              "description": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "due_at": {
                "format": "date-time",
                "type": [
                  "string",
                  "null"
                ]
              },
              "is_milestone": {
                "type": "boolean"
              },
              "milestone_amount_minor": {
                "format": "int64",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "milestone_currency": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "phase_id": {
                "format": "uuid",
                "type": [
                  "string",
                  "null"
                ]
              },
              "sort_order": {
                "format": "int32",
                "type": "integer"
              },
              "title": {
                "type": "string"
              }
            },
            "required": [
              "title"
            ],
            "type": "object"
          }
        ]
      },
      "CreateTemplateRequest": {
        "properties": {
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "type": "string"
          },
          "spec": {
            "description": "Versioned template spec (core-projects `template`, spec_version 1).\nValidated eagerly so broken blueprints never persist."
          }
        },
        "required": [
          "name",
          "spec"
        ],
        "type": "object"
      },
      "CreateTicketRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1): idempotency key + entity\nversion. Absent in legacy clients — purely additive."
          },
          {
            "properties": {
              "assignee_id": {
                "format": "uuid",
                "type": [
                  "string",
                  "null"
                ]
              },
              "board_id": {
                "format": "uuid",
                "type": "string"
              },
              "body": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "client_id": {
                "format": "uuid",
                "type": [
                  "string",
                  "null"
                ]
              },
              "contact_id": {
                "format": "uuid",
                "type": [
                  "string",
                  "null"
                ]
              },
              "custom_fields": {
                "description": "Initial custom-field values; each is validated against its\ndefinition. REQUIRED definitions must all be present (TASKLIST 2.17).",
                "items": {
                  "$ref": "#/components/schemas/TicketFieldInput"
                },
                "type": "array"
              },
              "due_at": {
                "format": "date-time",
                "type": [
                  "string",
                  "null"
                ]
              },
              "priority": {
                "$ref": "#/components/schemas/Priority"
              },
              "site_id": {
                "format": "uuid",
                "type": [
                  "string",
                  "null"
                ]
              },
              "title": {
                "type": "string"
              }
            },
            "required": [
              "board_id",
              "title",
              "priority"
            ],
            "type": "object"
          }
        ]
      },
      "CreateTimeEntryRequest": {
        "properties": {
          "billable": {
            "type": "boolean"
          },
          "ended_at": {
            "format": "date-time",
            "type": "string"
          },
          "notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "started_at": {
            "format": "date-time",
            "type": "string"
          },
          "ticket_id": {
            "format": "uuid",
            "type": "string"
          },
          "work_type": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "ticket_id",
          "started_at",
          "ended_at",
          "billable"
        ],
        "type": "object"
      },
      "CreateTravelDraftRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams"
          },
          {
            "properties": {
              "billable": {
                "type": "boolean"
              },
              "distance": {
                "format": "double",
                "type": "number"
              },
              "distance_unit": {
                "description": "`km` | `mi`.",
                "type": "string"
              },
              "ended_at": {
                "format": "date-time",
                "type": "string"
              },
              "notes": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "started_at": {
                "format": "date-time",
                "type": "string"
              },
              "ticket_id": {
                "format": "uuid",
                "type": "string"
              },
              "user_id": {
                "description": "Whose work this is; defaults to the caller. Only owner/admin may\nfile on someone else's behalf.",
                "format": "uuid",
                "type": [
                  "string",
                  "null"
                ]
              },
              "vehicle": {
                "type": "string"
              }
            },
            "required": [
              "ticket_id",
              "started_at",
              "ended_at",
              "distance",
              "distance_unit",
              "vehicle"
            ],
            "type": "object"
          }
        ],
        "description": "POST /api/dispatch/travel-drafts body."
      },
      "CreateViewRequest": {
        "properties": {
          "is_default": {
            "type": "boolean"
          },
          "name": {
            "type": "string"
          },
          "project_id": {
            "description": "`None` = org-wide view (spans every project).",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "spec": {
            "description": "Versioned, additive-only view spec (filter/group/sort). Consumers\ntolerate unknown fields."
          }
        },
        "required": [
          "name"
        ],
        "type": "object"
      },
      "CreateWebhookRequest": {
        "properties": {
          "event_types": {
            "description": "Exact event types to subscribe; empty subscribes to everything.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "url": {
            "description": "HTTPS endpoint receiving `POST`s. (http:// allowed for local dev.)",
            "type": "string"
          }
        },
        "required": [
          "url"
        ],
        "type": "object"
      },
      "CustomizationManifest": {
        "description": "The customization manifest envelope, `manifest_version` 1.",
        "properties": {
          "generated_at": {
            "description": "Dump instant (excluded from determinism comparisons).",
            "format": "date-time",
            "type": "string"
          },
          "manifest_version": {
            "description": "Envelope schema version. Bump ONLY for breaking section reshapes.",
            "format": "int32",
            "minimum": 0,
            "type": "integer"
          },
          "org_id": {
            "description": "The org this manifest documents.",
            "format": "uuid",
            "type": "string"
          },
          "sections": {
            "$ref": "#/components/schemas/ManifestSections",
            "description": "The customization sections. Always fully serialized."
          }
        },
        "required": [
          "manifest_version",
          "org_id",
          "generated_at",
          "sections"
        ],
        "type": "object"
      },
      "DayCapacity": {
        "description": "One technician's capacity for one day of the horizon.",
        "properties": {
          "available_minutes": {
            "description": "Availability coverage minus exclusions for the UTC day.",
            "format": "int64",
            "type": "integer"
          },
          "booked_minutes": {
            "description": "Live booking minutes clipped to the day.",
            "format": "int64",
            "type": "integer"
          },
          "date": {
            "format": "date",
            "type": "string"
          },
          "free_minutes": {
            "description": "What a NEW booking can still consume: availability minus\nexclusions minus existing bookings.",
            "format": "int64",
            "type": "integer"
          },
          "utilization_percent": {
            "description": "0–100+, where >100 is over-capacity.",
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "date",
          "available_minutes",
          "booked_minutes",
          "free_minutes",
          "utilization_percent"
        ],
        "type": "object"
      },
      "DayWeekQuery": {
        "properties": {
          "date": {
            "description": "Local date in the TARGET user's timezone. Day view: the day itself.\nWeek view: any date inside the week (Monday-start). Defaults to\ntoday in that timezone.",
            "type": [
              "string",
              "null"
            ]
          },
          "user_id": {
            "description": "Whose calendar. Defaults to the caller; another user requires\nowner/admin.",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "DecideAppointmentRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1): idempotency key + If-Match\n`version` on the request."
          },
          {
            "properties": {
              "decision_note": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "type": "object"
          }
        ],
        "description": "A staff decision body. `decision_note` is the (optional) reason shown\nto the client on decline and a confirmation note on approve."
      },
      "DecideProposalRequest": {
        "properties": {
          "note": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "DecideResponse": {
        "description": "Instant-first mutation response (IF2) for a decision. `appointment`\nis present ONLY on approve: the calendar booking this decision made.",
        "properties": {
          "appointment": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/Appointment"
              }
            ]
          },
          "mutation": {
            "$ref": "#/components/schemas/MutationMeta"
          },
          "request": {
            "$ref": "#/components/schemas/AppointmentRequest"
          }
        },
        "required": [
          "request",
          "mutation"
        ],
        "type": "object"
      },
      "DeclarationView": {
        "description": "Wire shape of one declaration. Kinds/options are flattened so generated\nclients can render editors directly from this payload.",
        "properties": {
          "default": {
            "$ref": "#/components/schemas/SettingValue"
          },
          "description": {
            "type": "string"
          },
          "key": {
            "type": "string"
          },
          "kind": {
            "$ref": "#/components/schemas/SettingKind"
          },
          "label": {
            "type": "string"
          },
          "options": {
            "description": "Closed option set for enumerations; empty otherwise.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "scope": {
            "description": "\"org\" | \"user\"",
            "type": "string"
          },
          "section": {
            "description": "Settings-hub section this declaration renders under.",
            "type": "string"
          },
          "visibility": {
            "description": "\"ui\" renders an editable row; \"hidden\" is state readable via values.",
            "type": "string"
          }
        },
        "required": [
          "key",
          "kind",
          "default",
          "scope",
          "section",
          "visibility",
          "label",
          "description",
          "options"
        ],
        "type": "object"
      },
      "DefinitionScope": {
        "description": "Visibility scope of a stored definition: `org` (published org-wide,\nadmins only) or `self` (private to the creator).",
        "enum": [
          "org",
          "self"
        ],
        "type": "string"
      },
      "DeliveryAttemptView": {
        "properties": {
          "attempt": {
            "format": "int32",
            "type": "integer"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "delivered_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "event_id": {
            "format": "uuid",
            "type": "string"
          },
          "event_type": {
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "last_error": {
            "type": [
              "string",
              "null"
            ]
          },
          "next_retry_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "response_status": {
            "description": "HTTP status when a response arrived; null for transport failures.",
            "format": "int32",
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "event_id",
          "event_type",
          "attempt",
          "created_at"
        ],
        "type": "object"
      },
      "DeliveryPage": {
        "properties": {
          "deliveries": {
            "items": {
              "$ref": "#/components/schemas/DeliveryAttemptView"
            },
            "type": "array"
          },
          "next_cursor": {
            "description": "Opaque keyset cursor for the next page; absent when exhausted.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "deliveries"
        ],
        "type": "object"
      },
      "DeliveryQuery": {
        "properties": {
          "cursor": {
            "type": [
              "string",
              "null"
            ]
          },
          "limit": {
            "format": "int64",
            "type": "integer"
          }
        },
        "type": "object"
      },
      "DependencyListResponse": {
        "description": "A task's direct finish-to-start dependencies (full rows, so the client\nrenders \"blocked by\" without extra fetches).",
        "properties": {
          "depends_on": {
            "items": {
              "$ref": "#/components/schemas/ProjectTask"
            },
            "type": "array"
          },
          "project_id": {
            "format": "uuid",
            "type": "string"
          },
          "task_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "task_id",
          "project_id",
          "depends_on"
        ],
        "type": "object"
      },
      "DeviceAsset": {
        "properties": {
          "client_id": {
            "format": "uuid",
            "type": "string"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "kind": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "site_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string"
          },
          "tag": {
            "description": "Human asset tag, e.g. \"EXCH-01\".",
            "type": "string"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "client_id",
          "tag",
          "name",
          "kind",
          "status",
          "created_at",
          "updated_at"
        ],
        "type": "object"
      },
      "DispatchAppointment": {
        "description": "One booking block on the dispatch board: the appointment plus the\nticket number and client name the block face renders.",
        "properties": {
          "client_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "client_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "dispatch_status": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/DispatchStatusShade",
                "description": "Latest field-service status push against this booking (dispatch v2,\nadditive): `None` when nothing was pushed yet."
              }
            ]
          },
          "ends_at": {
            "format": "date-time",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "kind": {
            "$ref": "#/components/schemas/AppointmentKind"
          },
          "starts_at": {
            "format": "date-time",
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/AppointmentStatus"
          },
          "ticket_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "ticket_number": {
            "type": [
              "string",
              "null"
            ]
          },
          "title": {
            "type": "string"
          },
          "travel_minutes": {
            "format": "int32",
            "type": "integer"
          },
          "user_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "id",
          "user_id",
          "title",
          "starts_at",
          "ends_at",
          "kind",
          "status",
          "travel_minutes"
        ],
        "type": "object"
      },
      "DispatchDayQuery": {
        "description": "One dispatch-path query: `date` is a LOCAL date interpreted as the\nUTC day window (documented UTC scope).",
        "properties": {
          "date": {
            "description": "The day to assemble; defaults to today (UTC).",
            "format": "date",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "DispatchDayView": {
        "description": "The assembled day-view payload: one request, one render.",
        "properties": {
          "date": {
            "format": "date",
            "type": "string"
          },
          "from": {
            "format": "date-time",
            "type": "string"
          },
          "technicians": {
            "items": {
              "$ref": "#/components/schemas/TechnicianView"
            },
            "type": "array"
          },
          "to": {
            "format": "date-time",
            "type": "string"
          },
          "unassigned": {
            "description": "Unassigned, non-closed tickets in dispatch order (priority rank,\nthen effective SLA/due deadline).",
            "items": {
              "$ref": "#/components/schemas/MyWorkItem"
            },
            "type": "array"
          }
        },
        "required": [
          "date",
          "from",
          "to",
          "technicians",
          "unassigned"
        ],
        "type": "object"
      },
      "DispatchQueueQuery": {
        "properties": {
          "limit": {
            "description": "Page size, clamped to [1, 500].",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "DispatchQueueView": {
        "description": "GET /api/dispatch/queue envelope.",
        "properties": {
          "queue": {
            "items": {
              "$ref": "#/components/schemas/QueuedTicket"
            },
            "type": "array"
          }
        },
        "required": [
          "queue"
        ],
        "type": "object"
      },
      "DispatchStatusShade": {
        "description": "The latest connector/staff status push for one booking, shaded onto\nthe board block face.",
        "properties": {
          "note": {
            "type": [
              "string",
              "null"
            ]
          },
          "occurred_at": {
            "format": "date-time",
            "type": "string"
          },
          "source": {
            "description": "`connector` | `staff`.",
            "type": "string"
          },
          "status": {
            "type": "string"
          }
        },
        "required": [
          "status",
          "source",
          "occurred_at"
        ],
        "type": "object"
      },
      "Document": {
        "description": "A document's living handle. No content lives here — content is only\never a [`DocumentVersion`]; `current_version` names the newest one.",
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "created_by": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "current_version": {
            "description": "The newest version number in the document's history.",
            "format": "int32",
            "type": "integer"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          },
          "updated_by": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "org_id",
          "title",
          "current_version",
          "created_at",
          "updated_at"
        ],
        "type": "object"
      },
      "DocumentListQuery": {
        "properties": {
          "q": {
            "description": "Title substring narrowing; ranked full-text search rides /api/search.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "DocumentMutationResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Document"
          },
          {
            "properties": {
              "mutation": {
                "$ref": "#/components/schemas/MutationMeta"
              }
            },
            "required": [
              "mutation"
            ],
            "type": "object"
          }
        ],
        "description": "Instant-first mutation response (IF2): document fields at the top\nlevel plus the additive `mutation` metadata."
      },
      "DocumentVersion": {
        "description": "One immutable snapshot in a document's append-only history. Every\nversion stores its complete title + body, so any pair is diffable\nwithout reconstructing intermediate state.",
        "properties": {
          "author_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "body": {
            "type": "string"
          },
          "change_summary": {
            "description": "Optional human explanation of what changed in this version.",
            "type": "string"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "document_id": {
            "format": "uuid",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "restored_from_version": {
            "description": "Set when this version was created by a RESTORE: the historical\nversion whose content was copied. Restore-creates-new-version is\nthe only way old content comes back — history is never rewritten.",
            "format": "int32",
            "type": [
              "integer",
              "null"
            ]
          },
          "title": {
            "type": "string"
          },
          "version": {
            "description": "1-based, gap-free per document.",
            "format": "int32",
            "type": "integer"
          }
        },
        "required": [
          "id",
          "org_id",
          "document_id",
          "version",
          "title",
          "created_at"
        ],
        "type": "object"
      },
      "DocumentView": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Document"
          },
          {
            "properties": {
              "body": {
                "type": "string"
              },
              "change_summary": {
                "type": "string"
              },
              "content_updated_at": {
                "format": "date-time",
                "type": "string"
              },
              "restored_from_version": {
                "format": "int32",
                "type": [
                  "integer",
                  "null"
                ]
              }
            },
            "required": [
              "body",
              "change_summary",
              "content_updated_at"
            ],
            "type": "object"
          }
        ],
        "description": "GET /api/documents/{id} response: the living handle plus the CURRENT\nversion's content (read-your-write on the body the last write stored)."
      },
      "DryRunRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/RowsPayload"
          },
          {
            "properties": {
              "conflict_policy": {
                "$ref": "#/components/schemas/ConflictPolicy"
              },
              "entity_kind": {
                "$ref": "#/components/schemas/EntityKind"
              },
              "label": {
                "description": "Free-form run label recorded with the dry-run history entry.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "template_id": {
                "description": "Optional saved field-mapping template: source headers are renamed to\nthe template's canonical columns before validation (D2 remainder).",
                "format": "uuid",
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "entity_kind",
              "conflict_policy"
            ],
            "type": "object"
          }
        ],
        "description": "POST /api/imports/dry-run request: validate a full payload and report\nwhat each row WOULD do before any data write. The probe is recorded as a\nfinished dry-run batch for operator history."
      },
      "DunningState": {
        "description": "Collections posture of an issued invoice. Forward-only: states are\ndata moved by explicit API writes (events + write trail), never a\nbackground side effect.",
        "enum": [
          "none",
          "reminder_sent",
          "overdue",
          "final_notice",
          "collections"
        ],
        "type": "string"
      },
      "DunningTransitionRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1): idempotency key +\nIf-Match `version` on the invoice."
          },
          {
            "properties": {
              "note": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "to_state": {
                "$ref": "#/components/schemas/DunningState",
                "description": "The target state; must be strictly forward on the ladder\n(skipping rungs is allowed)."
              }
            },
            "required": [
              "to_state"
            ],
            "type": "object"
          }
        ]
      },
      "EffectsRequest": {
        "properties": {
          "actions": {
            "description": "AutomationAction documents, parsed and validated via core-domain."
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "rule_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "ticket_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "org_id",
          "ticket_id",
          "actions"
        ],
        "type": "object"
      },
      "EntityKind": {
        "description": "Which entity family a batch targets. One batch = exactly one kind; the\nparent-before-child ordering across batches keeps foreign references\nresolvable without cross-batch transactions. D2 remainder extends the\noriginal client/site/contact family with boards, tickets, and time\nentries: [`Self::import_order`] is the documented run-script order.",
        "enum": [
          "client",
          "site",
          "contact",
          "board",
          "ticket",
          "time_entry",
          "kb_category",
          "kb_article"
        ],
        "type": "string"
      },
      "EscalationStep": {
        "description": "One escalation ladder step as stored (`sla_escalation_steps`).",
        "properties": {
          "at_pct": {
            "format": "int64",
            "type": "integer"
          },
          "enabled": {
            "type": "boolean"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "notify_user_ids": {
            "description": "Extra recipients beyond the ticket assignee.",
            "items": {
              "format": "uuid",
              "type": "string"
            },
            "type": "array"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "policy_id": {
            "format": "uuid",
            "type": "string"
          },
          "step_index": {
            "format": "int32",
            "type": "integer"
          },
          "trigger_kind": {
            "description": "'risk' | 'breach' | 'escalate' — bound to existing notification kinds.",
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "policy_id",
          "step_index",
          "trigger_kind",
          "at_pct",
          "notify_user_ids",
          "enabled"
        ],
        "type": "object"
      },
      "ExportBundle": {
        "description": "The org-data export envelope, `bundle_version` 1.",
        "properties": {
          "bundle_version": {
            "description": "Envelope schema version. Bump ONLY for breaking section reshapes.",
            "format": "int32",
            "minimum": 0,
            "type": "integer"
          },
          "generated_at": {
            "description": "Dump instant (excluded from determinism comparisons).",
            "format": "date-time",
            "type": "string"
          },
          "org_id": {
            "description": "The org this bundle documents.",
            "format": "uuid",
            "type": "string"
          },
          "sections": {
            "$ref": "#/components/schemas/ExportSections",
            "description": "The export sections. Always fully serialized."
          }
        },
        "required": [
          "bundle_version",
          "org_id",
          "generated_at",
          "sections"
        ],
        "type": "object"
      },
      "ExportClient": {
        "description": "One client company row.",
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "restricted_to": {
            "description": "Optional visibility restriction: when non-empty, only these users\n(plus admins) can see the client. Opaque user-id references.",
            "items": {
              "format": "uuid",
              "type": "string"
            },
            "type": "array"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "id",
          "name",
          "restricted_to",
          "created_at",
          "updated_at"
        ],
        "type": "object"
      },
      "ExportComment": {
        "description": "One ticket comment.",
        "properties": {
          "author_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "body": {
            "type": "string"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "kind": {
            "$ref": "#/components/schemas/NoteKind",
            "description": "Structured note taxonomy: internal | client_visible | in_house_update."
          }
        },
        "required": [
          "id",
          "author_id",
          "kind",
          "body",
          "created_at"
        ],
        "type": "object"
      },
      "ExportContact": {
        "description": "One contact row; `client_id`/`site_id` reference this bundle.",
        "properties": {
          "client_id": {
            "format": "uuid",
            "type": "string"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "email": {
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "is_primary": {
            "type": "boolean"
          },
          "name": {
            "type": "string"
          },
          "phone": {
            "type": [
              "string",
              "null"
            ]
          },
          "site_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "title": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "client_id",
          "site_id",
          "name",
          "is_primary",
          "created_at"
        ],
        "type": "object"
      },
      "ExportCreatedResponse": {
        "properties": {
          "bundle_version": {
            "description": "Envelope version of the produced bundle (mirrors the body).",
            "format": "int32",
            "minimum": 0,
            "type": "integer"
          },
          "download_url": {
            "description": "Self-contained relative URL carrying the signature + expiry; the\nclient prefixes its API origin. Works without a bearer token.",
            "type": "string"
          },
          "expires_at": {
            "format": "date-time",
            "type": "string"
          },
          "export_id": {
            "format": "uuid",
            "type": "string"
          },
          "sha256": {
            "description": "sha256 of the stored bytes (download integrity check).",
            "type": "string"
          },
          "size_bytes": {
            "description": "Exact bundle byte size as stored.",
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "export_id",
          "download_url",
          "expires_at",
          "size_bytes",
          "sha256",
          "bundle_version"
        ],
        "type": "object"
      },
      "ExportFieldValue": {
        "description": "One typed custom-field value attached to any entity row.",
        "properties": {
          "entity": {
            "description": "Field-definition family the value belongs to (ticket | client |\ncontact | asset) — resolved from the definition at load time.",
            "type": "string"
          },
          "entity_id": {
            "format": "uuid",
            "type": "string"
          },
          "field_id": {
            "format": "uuid",
            "type": "string"
          },
          "value": {
            "description": "The typed value exactly as stored (JSONB passthrough).",
            "type": "object"
          }
        },
        "required": [
          "entity",
          "entity_id",
          "field_id",
          "value"
        ],
        "type": "object"
      },
      "ExportOrg": {
        "description": "Org profile identity.",
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "ticket_prefix": {
            "description": "Human ticket-number prefix (e.g. \"MER\").",
            "type": "string"
          }
        },
        "required": [
          "name",
          "slug",
          "ticket_prefix",
          "created_at"
        ],
        "type": "object"
      },
      "ExportSections": {
        "description": "Section container — all fields always present; empty org state is an\nempty array, never an absent key.",
        "properties": {
          "clients": {
            "items": {
              "$ref": "#/components/schemas/ExportClient"
            },
            "type": "array"
          },
          "contacts": {
            "items": {
              "$ref": "#/components/schemas/ExportContact"
            },
            "type": "array"
          },
          "custom_field_values": {
            "description": "Every custom-field VALUE in the org, flat across entity families —\nthe data plane the U5 manifest deliberately excludes. `entity` names\nthe family the field definition attaches to (ticket | client |\ncontact | asset); `entity_id` is the owning row.",
            "items": {
              "$ref": "#/components/schemas/ExportFieldValue"
            },
            "type": "array"
          },
          "customization": {
            "$ref": "#/components/schemas/ManifestSections",
            "description": "The U5 customization-manifest sections, embedded verbatim — D1 is\nthe manifest's generalization, not its replacement."
          },
          "org": {
            "$ref": "#/components/schemas/ExportOrg",
            "description": "Org profile identity (volatile counters excluded — a restore\nreseeds the ticket-number sequence from the imported tickets)."
          },
          "sites": {
            "items": {
              "$ref": "#/components/schemas/ExportSite"
            },
            "type": "array"
          },
          "tickets": {
            "description": "Tickets with their comments nested. Parents (client/site/contact)\nare referenced by id into the sections above.",
            "items": {
              "$ref": "#/components/schemas/ExportTicket"
            },
            "type": "array"
          },
          "time_entries": {
            "items": {
              "$ref": "#/components/schemas/ExportTimeEntry"
            },
            "type": "array"
          }
        },
        "required": [
          "customization",
          "org",
          "clients",
          "sites",
          "contacts",
          "tickets",
          "time_entries",
          "custom_field_values"
        ],
        "type": "object"
      },
      "ExportSite": {
        "description": "One site row; `client_id` references `clients` in this bundle.",
        "properties": {
          "address": {
            "type": [
              "string",
              "null"
            ]
          },
          "city": {
            "type": [
              "string",
              "null"
            ]
          },
          "client_id": {
            "format": "uuid",
            "type": "string"
          },
          "country": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "latitude": {
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          },
          "longitude": {
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          },
          "name": {
            "type": "string"
          },
          "postal_code": {
            "type": [
              "string",
              "null"
            ]
          },
          "region": {
            "type": [
              "string",
              "null"
            ]
          },
          "timezone": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "client_id",
          "name",
          "created_at"
        ],
        "type": "object"
      },
      "ExportTicket": {
        "description": "One ticket with its comment thread nested. Authorship is an opaque\nuser-id reference; the bundle never carries user records.",
        "properties": {
          "assignee_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "board_id": {
            "format": "uuid",
            "type": "string"
          },
          "body": {
            "type": [
              "string",
              "null"
            ]
          },
          "category": {
            "$ref": "#/components/schemas/TicketStatusCategory",
            "description": "Semantic category of the captured status (behavior binds to this,\nnever to the status label)."
          },
          "client_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "comments": {
            "items": {
              "$ref": "#/components/schemas/ExportComment"
            },
            "type": "array"
          },
          "contact_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "due_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "number": {
            "description": "Human number (e.g. \"MER-12\") — the bundle's stable ticket key.",
            "type": "string"
          },
          "priority": {
            "$ref": "#/components/schemas/Priority"
          },
          "requester_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "resolved_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "site_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "status_id": {
            "format": "uuid",
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "id",
          "number",
          "board_id",
          "status_id",
          "title",
          "priority",
          "category",
          "client_id",
          "site_id",
          "contact_id",
          "assignee_id",
          "requester_id",
          "created_at",
          "updated_at",
          "comments"
        ],
        "type": "object"
      },
      "ExportTimeEntry": {
        "description": "One time entry; `ticket_id` and `user_id` reference this bundle's\ntickets and the org's live users respectively.",
        "properties": {
          "billable": {
            "type": "boolean"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "ended_at": {
            "format": "date-time",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "minutes": {
            "format": "int64",
            "type": "integer"
          },
          "notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "started_at": {
            "format": "date-time",
            "type": "string"
          },
          "ticket_id": {
            "format": "uuid",
            "type": "string"
          },
          "user_id": {
            "format": "uuid",
            "type": "string"
          },
          "work_type": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "ticket_id",
          "user_id",
          "started_at",
          "ended_at",
          "minutes",
          "billable",
          "created_at"
        ],
        "type": "object"
      },
      "FavoriteRequest": {
        "properties": {
          "board_id": {
            "format": "uuid",
            "type": "string"
          },
          "favorite": {
            "type": "boolean"
          }
        },
        "required": [
          "board_id",
          "favorite"
        ],
        "type": "object"
      },
      "FeeSpec": {
        "description": "Fixed-fee schedule entry spec.",
        "properties": {
          "amount_minor": {
            "format": "int64",
            "type": "integer"
          },
          "due_on": {
            "format": "date",
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "notes": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "label",
          "amount_minor",
          "due_on"
        ],
        "type": "object"
      },
      "FieldDefView": {
        "description": "Wire view of one field definition; choice kinds carry their closed\noption set so generated clients can render editors directly.",
        "properties": {
          "board_id": {
            "description": "Owning board (`None` = org-wide; v1 always creates board-scoped).",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "entity": {
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "kind": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "options": {
            "description": "Closed option set for select/multiselect; empty otherwise.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "required": {
            "type": "boolean"
          },
          "sort_order": {
            "format": "int32",
            "type": "integer"
          }
        },
        "required": [
          "id",
          "org_id",
          "entity",
          "name",
          "kind",
          "options",
          "required",
          "sort_order"
        ],
        "type": "object"
      },
      "FieldKindWire": {
        "description": "The definition kinds (mirror of migration 0009's CHECK set). Kept as a\nstring-newtype wire enum so unknown kinds fail validation, not deserialization.",
        "enum": [
          "text",
          "number",
          "date",
          "select",
          "multiselect",
          "bool",
          "url",
          "user"
        ],
        "type": "string"
      },
      "FilterOp": {
        "description": "Filter operators supported by the v1 compiled reports. Operand typing is\nenforced through [`ValueType`] matches in the builder, so e.g. a bool\noperand can never reach a timestamp column. The serde encoding is the\n`snake_case` slug (`lt_eq`, `is_null`, …) stored specs carry.",
        "enum": [
          "eq",
          "not_eq",
          "lt",
          "lt_eq",
          "gt",
          "gt_eq",
          "is_null",
          "is_not_null"
        ],
        "type": "string"
      },
      "FilterValue": {
        "description": "A typed filter operand. The variant must match the catalog\n[`ValueType`] of the filtered column (`Int` covers both Int and BigInt\ncolumns) — enforced by [`ReportSpec::validate`], so a mismatched\noperand can never reach a bind. The serde encoding is the externally\ntagged slug (`{\"text\": \"p1\"}`, `{\"bool\": true}`).",
        "oneOf": [
          {
            "properties": {
              "uuid": {
                "format": "uuid",
                "type": "string"
              }
            },
            "required": [
              "uuid"
            ],
            "type": "object"
          },
          {
            "properties": {
              "text": {
                "type": "string"
              }
            },
            "required": [
              "text"
            ],
            "type": "object"
          },
          {
            "description": "RFC 3339 instant (chrono serde encoding).",
            "properties": {
              "timestamp": {
                "description": "RFC 3339 instant (chrono serde encoding).",
                "format": "date-time",
                "type": "string"
              }
            },
            "required": [
              "timestamp"
            ],
            "type": "object"
          },
          {
            "description": "`YYYY-MM-DD`.",
            "properties": {
              "date": {
                "description": "`YYYY-MM-DD`.",
                "format": "date",
                "type": "string"
              }
            },
            "required": [
              "date"
            ],
            "type": "object"
          },
          {
            "properties": {
              "int": {
                "format": "int64",
                "type": "integer"
              }
            },
            "required": [
              "int"
            ],
            "type": "object"
          },
          {
            "properties": {
              "bool": {
                "type": "boolean"
              }
            },
            "required": [
              "bool"
            ],
            "type": "object"
          }
        ]
      },
      "GapDayView": {
        "properties": {
          "activity": {
            "type": "boolean"
          },
          "day": {
            "description": "Local calendar day (YYYY-MM-DD).",
            "type": "string"
          },
          "expected_minutes": {
            "format": "int64",
            "type": "integer"
          },
          "has_gap": {
            "type": "boolean"
          },
          "logged_minutes": {
            "format": "int64",
            "type": "integer"
          },
          "nudge_sent_at": {
            "description": "When the EOD run nudged for this day, if it did.",
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "unaccounted_minutes": {
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "day",
          "activity",
          "logged_minutes",
          "expected_minutes",
          "has_gap",
          "unaccounted_minutes"
        ],
        "type": "object"
      },
      "GapReportQuery": {
        "properties": {
          "from": {
            "description": "Inclusive local-day start (YYYY-MM-DD). Defaults to yesterday.",
            "format": "date",
            "type": [
              "string",
              "null"
            ]
          },
          "to": {
            "description": "Inclusive local-day end (YYYY-MM-DD). Defaults to `from`.",
            "format": "date",
            "type": [
              "string",
              "null"
            ]
          },
          "user_id": {
            "description": "Manager report only: whose days. Requires owner/admin.",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "GapReportResponse": {
        "properties": {
          "days": {
            "items": {
              "$ref": "#/components/schemas/GapDayView"
            },
            "type": "array"
          },
          "expected_minutes": {
            "format": "int64",
            "type": "integer"
          },
          "timezone": {
            "type": "string"
          },
          "user_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "user_id",
          "timezone",
          "expected_minutes",
          "days"
        ],
        "type": "object"
      },
      "HealthResponse": {
        "properties": {
          "status": {
            "type": "string"
          }
        },
        "required": [
          "status"
        ],
        "type": "object"
      },
      "IncidentView": {
        "description": "The storm group behind an incident ticket.",
        "properties": {
          "alert_count": {
            "description": "How many alerts have collapsed into this ticket so far.",
            "format": "int32",
            "type": "integer"
          },
          "first_alert_at": {
            "type": "string"
          },
          "last_alert_at": {
            "type": "string"
          },
          "ticket_id": {
            "format": "uuid",
            "type": "string"
          },
          "ticket_number": {
            "type": "string"
          }
        },
        "required": [
          "ticket_id",
          "ticket_number",
          "alert_count",
          "first_alert_at",
          "last_alert_at"
        ],
        "type": "object"
      },
      "IngestAlertRequest": {
        "properties": {
          "attributes": {
            "description": "Provider-specific structured context (must be a JSON object)."
          },
          "correlation_key": {
            "description": "Storm grouping key; defaults to `dedup_key` when absent so\nuncorrelated alerts each anchor their own incident.",
            "type": [
              "string",
              "null"
            ]
          },
          "dedup_key": {
            "description": "Provider's per-event identity. REQUIRED: this is the replay gate.",
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "occurred_at": {
            "description": "When the condition started (defaults to receipt time).",
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "severity": {
            "$ref": "#/components/schemas/AlertSeverity"
          },
          "title": {
            "type": "string"
          }
        },
        "required": [
          "dedup_key",
          "title",
          "severity"
        ],
        "type": "object"
      },
      "IngestResponse": {
        "description": "POST /api/alerts/ingest — outcome of one signed delivery.",
        "properties": {
          "alert": {
            "$ref": "#/components/schemas/AlertView"
          },
          "incident": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/IncidentView",
                "description": "Present for `incident_created` and `collapsed`; `None` when the\nanchor ticket vanished before a replay answered."
              }
            ]
          },
          "status": {
            "description": "`incident_created` (this alert anchored a NEW incident ticket),\n`collapsed` (folded into the still-open storm incident), or\n`duplicate` (replayed dedup_key — the stored alert is returned,\nnothing was written).",
            "type": "string"
          }
        },
        "required": [
          "status",
          "alert"
        ],
        "type": "object"
      },
      "InstantiateTemplateRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1): idempotency key + entity\nversion (of the newly created project). Absent in legacy clients —\npurely additive."
          },
          {
            "properties": {
              "assignee_map": {
                "additionalProperties": {
                  "format": "uuid",
                  "type": "string"
                },
                "description": "Resolves template `assignee_key`s to user ids at instantiation\ntime; unmapped keys simply leave those tasks unassigned.",
                "propertyNames": {
                  "type": "string"
                },
                "type": "object"
              },
              "client_id": {
                "format": "uuid",
                "type": [
                  "string",
                  "null"
                ]
              },
              "due_date": {
                "format": "date",
                "type": [
                  "string",
                  "null"
                ]
              },
              "name": {
                "type": "string"
              },
              "start_date": {
                "format": "date",
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "name"
            ],
            "type": "object"
          }
        ]
      },
      "Invoice": {
        "description": "The billing document. Derives from exactly one contract; `currency`\nand `total_minor` come from the contract's evaluation (line sum).",
        "properties": {
          "client_id": {
            "format": "uuid",
            "type": "string"
          },
          "contract_id": {
            "format": "uuid",
            "type": "string"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "created_by": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "currency": {
            "description": "ISO 4217 code copied from the contract; every amount uses it.",
            "type": "string"
          },
          "due_on": {
            "format": "date",
            "type": "string"
          },
          "dunning_note": {
            "type": [
              "string",
              "null"
            ]
          },
          "dunning_state": {
            "$ref": "#/components/schemas/DunningState"
          },
          "dunning_updated_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "issued_at": {
            "format": "date",
            "type": "string"
          },
          "notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "number": {
            "description": "Human invoice number, unique per org (e.g. \"INV-000042\").",
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "period_from": {
            "description": "The billed period, when the contract type has one (recurring /\nretainer / T&M window slice); `None` for fixed-fee schedules.",
            "format": "date",
            "type": [
              "string",
              "null"
            ]
          },
          "period_to": {
            "format": "date",
            "type": [
              "string",
              "null"
            ]
          },
          "run_id": {
            "description": "The run that created this invoice (`None` for future manual invoices).",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "$ref": "#/components/schemas/InvoiceStatus"
          },
          "total_minor": {
            "description": "Sum of line amounts, minor units.",
            "format": "int64",
            "type": "integer"
          },
          "total_paid_minor": {
            "description": "Recorded payment total, minor units.",
            "format": "int64",
            "type": "integer"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "client_id",
          "contract_id",
          "number",
          "status",
          "currency",
          "issued_at",
          "due_on",
          "total_minor",
          "total_paid_minor",
          "dunning_state",
          "created_at",
          "updated_at"
        ],
        "type": "object"
      },
      "InvoiceDetail": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Invoice"
          },
          {
            "properties": {
              "lines": {
                "items": {
                  "$ref": "#/components/schemas/InvoiceLine"
                },
                "type": "array"
              },
              "payments": {
                "items": {
                  "$ref": "#/components/schemas/InvoicePayment"
                },
                "type": "array"
              }
            },
            "required": [
              "lines",
              "payments"
            ],
            "type": "object"
          }
        ],
        "description": "The invoice aggregate: document, lines, and payment receipts."
      },
      "InvoiceLine": {
        "description": "One persisted billing line; mirrors the engine's `BillingCandidateLine`\n(kind reuse via [`crate::entities::BillingLineKind`]) minus the\ndenormalized contract/client names.",
        "properties": {
          "amount_minor": {
            "format": "int64",
            "type": "integer"
          },
          "contract_id": {
            "format": "uuid",
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "invoice_id": {
            "format": "uuid",
            "type": "string"
          },
          "kind": {
            "$ref": "#/components/schemas/BillingLineKind"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "period_end": {
            "format": "date",
            "type": "string"
          },
          "period_start": {
            "format": "date",
            "type": "string"
          },
          "position": {
            "format": "int32",
            "type": "integer"
          },
          "quantity_minutes": {
            "description": "Labor minutes on the line (T&M / overage); 0 for amount lines.",
            "format": "int64",
            "type": "integer"
          },
          "unit_amount_minor": {
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "id",
          "org_id",
          "invoice_id",
          "contract_id",
          "kind",
          "description",
          "period_start",
          "period_end",
          "quantity_minutes",
          "unit_amount_minor",
          "amount_minor",
          "position"
        ],
        "type": "object"
      },
      "InvoiceListQuery": {
        "properties": {
          "client_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "contract_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "dunning_state": {
            "description": "Exact dunning state:\n`none|reminder_sent|overdue|final_notice|collections`.",
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "description": "Exact status: `draft|issued|paid|void`.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "InvoiceMutationResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Invoice"
          },
          {
            "properties": {
              "mutation": {
                "$ref": "#/components/schemas/MutationMeta"
              }
            },
            "required": [
              "mutation"
            ],
            "type": "object"
          }
        ],
        "description": "Instant-first mutation response (IF2) for invoice mutations."
      },
      "InvoicePayment": {
        "description": "A payment receipt recorded through the `PaymentProvider` seam. The\nprovider stays a string (`none` in v1 — the built-in provider approves\nlocally without external PSP calls).",
        "properties": {
          "amount_minor": {
            "format": "int64",
            "type": "integer"
          },
          "created_by": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "currency": {
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "invoice_id": {
            "format": "uuid",
            "type": "string"
          },
          "notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "provider": {
            "type": "string"
          },
          "provider_ref": {
            "type": [
              "string",
              "null"
            ]
          },
          "received_at": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "invoice_id",
          "amount_minor",
          "currency",
          "provider",
          "received_at"
        ],
        "type": "object"
      },
      "InvoiceRun": {
        "description": "The invoice-run batch record: one evaluation sweep over a window and\nthe roll-up of the invoices it created.",
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "created_by": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "currency": {
            "description": "Currency of the summed total; `None` when the run created no\ninvoices (mixed currencies are rejected before any write).",
            "type": [
              "string",
              "null"
            ]
          },
          "due_in_days": {
            "format": "int32",
            "type": "integer"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "invoice_count": {
            "format": "int32",
            "type": "integer"
          },
          "number": {
            "description": "Human run number, unique per org (e.g. \"RUN-000007\").",
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "period_from": {
            "format": "date",
            "type": "string"
          },
          "period_to": {
            "format": "date",
            "type": "string"
          },
          "total_minor": {
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "id",
          "org_id",
          "number",
          "period_from",
          "period_to",
          "invoice_count",
          "total_minor",
          "due_in_days",
          "created_at"
        ],
        "type": "object"
      },
      "InvoiceRunResponse": {
        "description": "Instant-first mutation response (IF2) for an invoice run.",
        "properties": {
          "invoices": {
            "items": {
              "$ref": "#/components/schemas/IssuedInvoice"
            },
            "type": "array"
          },
          "mutation": {
            "$ref": "#/components/schemas/MutationMeta"
          },
          "run": {
            "$ref": "#/components/schemas/InvoiceRun"
          }
        },
        "required": [
          "run",
          "invoices",
          "mutation"
        ],
        "type": "object"
      },
      "InvoiceStatus": {
        "description": "Document lifecycle of an invoice.",
        "enum": [
          "draft",
          "issued",
          "paid",
          "void"
        ],
        "type": "string"
      },
      "IssuedInvoice": {
        "description": "One issued invoice: the document plus its lines.",
        "properties": {
          "invoice": {
            "$ref": "#/components/schemas/Invoice"
          },
          "lines": {
            "items": {
              "$ref": "#/components/schemas/InvoiceLine"
            },
            "type": "array"
          }
        },
        "required": [
          "invoice",
          "lines"
        ],
        "type": "object"
      },
      "KbArticle": {
        "description": "A KB article.",
        "properties": {
          "body": {
            "type": "string"
          },
          "category_id": {
            "description": "Survives category deletion (the FK is ON DELETE SET NULL).",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "client_visible": {
            "description": "The article half of the client-facing gate (portal v2 honors it).",
            "type": "boolean"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "created_by": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "slug": {
            "description": "Stable per-org handle (unique).",
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/KbArticleStatus"
          },
          "title": {
            "type": "string"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          },
          "updated_by": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "org_id",
          "title",
          "slug",
          "status",
          "client_visible",
          "created_at",
          "updated_at"
        ],
        "type": "object"
      },
      "KbArticleStatus": {
        "description": "Article lifecycle. Closed vocabulary so filtering and the client-facing\nrule stay deterministic: `draft` (staff authoring), `published`\n(readable, searchable), `archived` (retired, out of the active tree —\ncontent edits are refused while archived; unarchive to edit).",
        "enum": [
          "draft",
          "published",
          "archived"
        ],
        "type": "string"
      },
      "KbCategory": {
        "description": "A KB category: grouping + ordering for the article tree.",
        "properties": {
          "client_visible": {
            "description": "The category half of the client-facing gate: an article is visible\nto portal clients only when this AND the article flag are set (and\nthe article is published).",
            "type": "boolean"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "position": {
            "format": "int32",
            "type": "integer"
          },
          "slug": {
            "description": "Stable per-org handle (unique); portals and imports reference this,\nnever the row id.",
            "type": "string"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "name",
          "slug",
          "position",
          "client_visible",
          "created_at",
          "updated_at"
        ],
        "type": "object"
      },
      "LadderStepSpec": {
        "properties": {
          "at_pct": {
            "description": "Fires when consumed budget reaches this percent (1..=500).",
            "format": "int64",
            "type": "integer"
          },
          "enabled": {
            "type": "boolean"
          },
          "notify_user_ids": {
            "items": {
              "format": "uuid",
              "type": "string"
            },
            "type": "array"
          },
          "step_index": {
            "format": "int32",
            "type": "integer"
          },
          "trigger_kind": {
            "description": "'risk' | 'breach' | 'escalate' (notification-center kinds).",
            "type": "string"
          }
        },
        "required": [
          "step_index",
          "trigger_kind",
          "at_pct",
          "notify_user_ids"
        ],
        "type": "object"
      },
      "LinkBeginResponse": {
        "properties": {
          "authorize_url": {
            "type": "string"
          }
        },
        "required": [
          "authorize_url"
        ],
        "type": "object"
      },
      "ListEntriesQuery": {
        "properties": {
          "limit": {
            "format": "int64",
            "type": "integer"
          },
          "since": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "ticket_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "user_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "ListTravelDraftsQuery": {
        "properties": {
          "limit": {
            "description": "Page size, clamped to [1, 200].",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "status": {
            "description": "`draft` | `submitted`.",
            "type": [
              "string",
              "null"
            ]
          },
          "user_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "LoginRequest": {
        "properties": {
          "email": {
            "type": "string"
          },
          "password": {
            "type": "string"
          }
        },
        "required": [
          "email",
          "password"
        ],
        "type": "object"
      },
      "LoginResponse": {
        "description": "Login outcome: tokens directly, or a short-lived MFA bridge token when\nany second factor is enrolled. Untagged so legacy clients that ignore\n`mfa_required` keep parsing the plain token pair they always got.",
        "oneOf": [
          {
            "$ref": "#/components/schemas/TokenPair"
          },
          {
            "properties": {
              "methods": {
                "description": "Second factors able to satisfy this login.",
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "mfa_required": {
                "type": "boolean"
              },
              "mfa_token": {
                "type": "string"
              }
            },
            "required": [
              "mfa_required",
              "mfa_token",
              "methods"
            ],
            "type": "object"
          }
        ]
      },
      "MaintenanceWindow": {
        "description": "Planned downtime: an absolute UTC interval during which SLA clocks do\nnot consume business-time budget (vendor maintenance, change freezes).",
        "properties": {
          "ends_at": {
            "format": "date-time",
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "starts_at": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "name",
          "starts_at",
          "ends_at"
        ],
        "type": "object"
      },
      "ManifestApiKey": {
        "description": "API-key metadata. `key_hash` (the credential verifier) and the raw key\nmaterial are structurally absent — only the display prefix survives.",
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "created_by": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "last_used_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "type": "string"
          },
          "prefix": {
            "description": "Non-secret display identifier (e.g. `mrd_ab12cd34`).",
            "type": "string"
          },
          "revoked_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "scopes": {
            "description": "Capability scope strings (\"tickets:read\", …).",
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "required": [
          "id",
          "name",
          "prefix",
          "scopes",
          "created_by",
          "created_at"
        ],
        "type": "object"
      },
      "ManifestAutomationRule": {
        "description": "One event-triggered automation rule.",
        "properties": {
          "actions": {
            "type": "object"
          },
          "board_id": {
            "description": "Board the rule is scoped to; null = every board in the org.",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "conditions": {
            "type": "object"
          },
          "enabled": {
            "type": "boolean"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "trigger_event": {
            "description": "Domain event type from the envelope, e.g. `ticket.created`.",
            "type": "string"
          }
        },
        "required": [
          "id",
          "board_id",
          "name",
          "trigger_event",
          "conditions",
          "actions",
          "enabled"
        ],
        "type": "object"
      },
      "ManifestBoard": {
        "description": "One board's workflow customization.",
        "properties": {
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "is_default": {
            "description": "The org's default intake board.",
            "type": "boolean"
          },
          "name": {
            "type": "string"
          },
          "require_checklist_close": {
            "description": "Pre-close checklist enforcement toggle (workflow discipline flag).",
            "type": "boolean"
          },
          "statuses": {
            "description": "Custom statuses; ALWAYS one per semantic category (defaults-first\nseeding guarantees category coverage, never removed by edits).",
            "items": {
              "$ref": "#/components/schemas/ManifestBoardStatus"
            },
            "type": "array"
          },
          "transitions": {
            "description": "Explicit transition adjacency between this board's statuses. Empty\nmeans the semantic-category floor applies (any→any except identity\nand closed→open), not \"no transitions\".",
            "items": {
              "$ref": "#/components/schemas/ManifestTransition"
            },
            "type": "array"
          }
        },
        "required": [
          "id",
          "name",
          "is_default",
          "require_checklist_close",
          "statuses",
          "transitions"
        ],
        "type": "object"
      },
      "ManifestBoardStatus": {
        "description": "One custom status, bound to its semantic category. Renames and colors\nnever change behavior — consumers must branch on `category`, not `name`.",
        "properties": {
          "category": {
            "$ref": "#/components/schemas/TicketStatusCategory",
            "description": "Semantic category: open | in_progress | waiting | closed. THE\nbinding every SLA/automation/reporting behavior keys on."
          },
          "color": {
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "is_entry": {
            "description": "Tickets may enter this status directly at creation.",
            "type": "boolean"
          },
          "name": {
            "type": "string"
          },
          "sort_order": {
            "format": "int32",
            "type": "integer"
          }
        },
        "required": [
          "id",
          "name",
          "category",
          "sort_order",
          "is_entry"
        ],
        "type": "object"
      },
      "ManifestCustomField": {
        "description": "One custom field definition. `config` is the kind-specific document\n(select options, validation bounds, …) exactly as stored.",
        "properties": {
          "archived_at": {
            "description": "Present when the definition was archived (still a customization the\npreflight must see; the values it shaped may still exist).",
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "config": {
            "type": "object"
          },
          "entity": {
            "description": "Entity the field attaches to: ticket | client | contact | asset.",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "kind": {
            "description": "Field kind: text | number | date | select | multiselect | bool | url | user.",
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "required": {
            "type": "boolean"
          },
          "sort_order": {
            "format": "int32",
            "type": "integer"
          }
        },
        "required": [
          "id",
          "entity",
          "name",
          "kind",
          "config",
          "required",
          "sort_order"
        ],
        "type": "object"
      },
      "ManifestEscalationStep": {
        "description": "One escalation ladder step.",
        "properties": {
          "at_pct": {
            "description": "Percent of the target's business-time budget consumed at firing.",
            "format": "int32",
            "type": "integer"
          },
          "enabled": {
            "type": "boolean"
          },
          "notify_user_ids": {
            "description": "JSON array of user ids to notify.",
            "type": "object"
          },
          "step_index": {
            "format": "int32",
            "type": "integer"
          },
          "trigger_kind": {
            "description": "risk | breach | escalate.",
            "type": "string"
          }
        },
        "required": [
          "step_index",
          "trigger_kind",
          "at_pct",
          "notify_user_ids",
          "enabled"
        ],
        "type": "object"
      },
      "ManifestReportDefinition": {
        "description": "One stored report definition (TASKLIST R3). The spec body rides as its\nstored jsonb document (`{filters, group_by, measures}`) exactly like\ncustom-field `config` — the registry-validated view/viz slugs travel as\ntheir own fields so a preflight can flag deprecated constructs without\nre-deriving validation. Nothing here is secret-bearing: definitions\nreference the read-model catalog only, never credentials or data.",
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "created_by": {
            "format": "uuid",
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "kind": {
            "description": "Registry-backed view slug (`tickets`, `time_entries`, …).",
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "scope": {
            "description": "Visibility scope: `org` (published org-wide) or `self` (private to\nthe creator; admins see all). Preflight-relevant because org-scope\ndefinitions are shared surface, self-scope ones are personal.",
            "type": "string"
          },
          "spec": {
            "description": "Spec body document: `{filters, group_by, measures}` as stored.",
            "type": "object"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          },
          "viz": {
            "description": "Visualization hint slug (`bar` | `line` | `pie` | `table`).",
            "type": "string"
          }
        },
        "required": [
          "id",
          "name",
          "kind",
          "spec",
          "viz",
          "scope",
          "created_by",
          "created_at",
          "updated_at"
        ],
        "type": "object"
      },
      "ManifestSections": {
        "description": "Section container. All fields are always present; empty org state is an\nempty array, never an absent key. New sections append here.",
        "properties": {
          "api_keys": {
            "description": "API-key metadata minus secret material (no hashes, no raw keys).",
            "items": {
              "$ref": "#/components/schemas/ManifestApiKey"
            },
            "type": "array"
          },
          "automation_rules": {
            "description": "Event-triggered automation rules.",
            "items": {
              "$ref": "#/components/schemas/ManifestAutomationRule"
            },
            "type": "array"
          },
          "boards": {
            "description": "Per-board workflow: the board identity plus its statuses (each bound\nto a semantic category — the defaults-first guarantee) and its\nexplicit transition adjacency. An EMPTY transitions array means the\nsemantic-category floor applies, not \"no transitions\".",
            "items": {
              "$ref": "#/components/schemas/ManifestBoard"
            },
            "type": "array"
          },
          "custom_fields": {
            "description": "Custom field definitions across all entities (tickets, clients,\ncontacts, assets), including archived ones.",
            "items": {
              "$ref": "#/components/schemas/ManifestCustomField"
            },
            "type": "array"
          },
          "report_definitions": {
            "description": "Stored report definitions (TASKLIST R3): registry-validated specs\nover the versioned read-model views. Covered so the upgrade\npreflight (U6) can flag any definition whose `kind`/spec columns\nreference deprecated view or column constructs (policy §5).",
            "items": {
              "$ref": "#/components/schemas/ManifestReportDefinition"
            },
            "type": "array"
          },
          "settings": {
            "description": "Org-scope settings-registry overrides (user-scope rows are per-user\npreferences, not org customization).",
            "items": {
              "$ref": "#/components/schemas/ManifestSetting"
            },
            "type": "array"
          },
          "sla": {
            "$ref": "#/components/schemas/ManifestSla",
            "description": "SLA configuration: calendars and policies with escalation ladders."
          },
          "webhooks": {
            "description": "Webhook subscriptions with event-type filters, never secrets.",
            "items": {
              "$ref": "#/components/schemas/ManifestWebhook"
            },
            "type": "array"
          }
        },
        "required": [
          "custom_fields",
          "boards",
          "automation_rules",
          "webhooks",
          "api_keys",
          "settings",
          "sla",
          "report_definitions"
        ],
        "type": "object"
      },
      "ManifestSetting": {
        "description": "One org-scope settings-registry override.",
        "properties": {
          "key": {
            "type": "string"
          },
          "value": {
            "type": "object"
          }
        },
        "required": [
          "key",
          "value"
        ],
        "type": "object"
      },
      "ManifestSla": {
        "description": "SLA configuration sections.",
        "properties": {
          "calendars": {
            "items": {
              "$ref": "#/components/schemas/ManifestSlaCalendar"
            },
            "type": "array"
          },
          "policies": {
            "items": {
              "$ref": "#/components/schemas/ManifestSlaPolicy"
            },
            "type": "array"
          }
        },
        "required": [
          "calendars",
          "policies"
        ],
        "type": "object"
      },
      "ManifestSlaCalendar": {
        "description": "One named SLA calendar row with its flattened business calendar body.",
        "properties": {
          "calendar": {
            "description": "Timezone / weekday windows / holidays / maintenance document.",
            "type": "object"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "name",
          "calendar"
        ],
        "type": "object"
      },
      "ManifestSlaPolicy": {
        "description": "One SLA policy with its targets document, embedded fallback calendar,\ncalendar attachment, and escalation ladder.",
        "properties": {
          "calendar": {
            "description": "Embedded fallback calendar; governs while `calendar_id` is null.",
            "type": "object"
          },
          "calendar_id": {
            "description": "Attached named calendar; null keeps the embedded one authoritative.",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "escalation_steps": {
            "description": "Escalation ladder steps, ordered by `step_index`.",
            "items": {
              "$ref": "#/components/schemas/ManifestEscalationStep"
            },
            "type": "array"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "is_default": {
            "type": "boolean"
          },
          "name": {
            "type": "string"
          },
          "targets": {
            "description": "Targets document keyed by priority string.",
            "type": "object"
          }
        },
        "required": [
          "id",
          "name",
          "is_default",
          "targets",
          "calendar",
          "calendar_id",
          "escalation_steps"
        ],
        "type": "object"
      },
      "ManifestTransition": {
        "description": "One allowed status change, `from` → `to`, both ids from the SAME board.",
        "properties": {
          "from_status_id": {
            "format": "uuid",
            "type": "string"
          },
          "to_status_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "from_status_id",
          "to_status_id"
        ],
        "type": "object"
      },
      "ManifestWebhook": {
        "description": "One webhook subscription. The HMAC signing secret is structurally\nabsent: it exists only at creation time and in the sealed column.",
        "properties": {
          "created_by": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "enabled": {
            "type": "boolean"
          },
          "event_types": {
            "description": "Event-type filter; empty array = wildcard (all event types).",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "url": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "url",
          "event_types",
          "enabled",
          "created_by"
        ],
        "type": "object"
      },
      "MarkReadBulkRequest": {
        "properties": {
          "ids": {
            "items": {
              "format": "uuid",
              "type": "string"
            },
            "type": "array"
          }
        },
        "required": [
          "ids"
        ],
        "type": "object"
      },
      "MarkReadResult": {
        "properties": {
          "marked": {
            "description": "Rows flipped from unread to read (idempotent under retry).",
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "marked"
        ],
        "type": "object"
      },
      "MatchCandidate": {
        "description": "One technician candidate for one ticket: the skills this candidate is\nmissing (an empty list = fully qualified right now).",
        "properties": {
          "display_name": {
            "type": "string"
          },
          "missing": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "user_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "user_id",
          "display_name",
          "missing"
        ],
        "type": "object"
      },
      "MatchQuery": {
        "description": "GET /api/dispatch/match query: how many unassigned tickets to match.",
        "properties": {
          "limit": {
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "MatchView": {
        "properties": {
          "matches": {
            "items": {
              "$ref": "#/components/schemas/TicketMatch"
            },
            "type": "array"
          }
        },
        "required": [
          "matches"
        ],
        "type": "object"
      },
      "MeResponse": {
        "properties": {
          "display_name": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "permissions": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "timezone": {
            "type": "string"
          },
          "user_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "user_id",
          "org_id",
          "email",
          "display_name",
          "timezone",
          "permissions"
        ],
        "type": "object"
      },
      "MeasureSpec": {
        "description": "One aggregate measure.",
        "properties": {
          "agg": {
            "$ref": "#/components/schemas/Aggregate"
          },
          "column": {
            "description": "`None` only with [`Aggregate::Count`] (`COUNT(*)`).",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "agg"
        ],
        "type": "object"
      },
      "MfaTokenRequest": {
        "properties": {
          "mfa_token": {
            "type": "string"
          }
        },
        "required": [
          "mfa_token"
        ],
        "type": "object"
      },
      "MfaVerifyRequest": {
        "properties": {
          "code": {
            "description": "TOTP code or recovery code.",
            "type": "string"
          },
          "mfa_token": {
            "description": "The `mfa_token` from POST /api/auth/login when mfa_required was set.",
            "type": "string"
          }
        },
        "required": [
          "mfa_token",
          "code"
        ],
        "type": "object"
      },
      "MoveAppointmentRequest": {
        "properties": {
          "ends_at": {
            "format": "date-time",
            "type": "string"
          },
          "starts_at": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "starts_at",
          "ends_at"
        ],
        "type": "object"
      },
      "MoveSpec": {
        "description": "One move in a batch: the booking's new user and slot.",
        "properties": {
          "appointment_id": {
            "format": "uuid",
            "type": "string"
          },
          "ends_at": {
            "format": "date-time",
            "type": "string"
          },
          "starts_at": {
            "format": "date-time",
            "type": "string"
          },
          "user_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "appointment_id",
          "user_id",
          "starts_at",
          "ends_at"
        ],
        "type": "object"
      },
      "MutationMeta": {
        "description": "Read-your-write metadata every mutation response carries (IF2), merged\nas the additive `mutation` object alongside the entity fields.",
        "properties": {
          "after": {
            "description": "Applied entity snapshot.",
            "type": "object"
          },
          "before": {
            "description": "Prior entity snapshot (the undo substrate). `null` on creates. The\nOpenAPI schema stays a plain object; generated clients get the\nruntime-typed view through the SDK's `snapshotOf` accessor.",
            "type": [
              "object",
              "null"
            ]
          },
          "idempotency_key": {
            "description": "The idempotency key that claimed this result, when the caller\nsupplied one.",
            "type": [
              "string",
              "null"
            ]
          },
          "seq": {
            "description": "Monotonic per-entity sequence: strictly increases by one per\napplied write, so clients order reconciliations against the event\nstream.",
            "format": "int64",
            "type": "integer"
          },
          "updated_at": {
            "description": "The applied entity's `updated_at`.",
            "type": "string"
          },
          "version": {
            "description": "Version token for If-Match-style writes; mirrors `seq`. Echo it in\nthe next write's `version` field.",
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "seq",
          "version",
          "updated_at",
          "before",
          "after"
        ],
        "type": "object"
      },
      "MutationParams": {
        "description": "The autosave mutation parameters every gated create/update body carries\n(flattened into the request struct — purely additive fields).",
        "properties": {
          "idempotency_key": {
            "description": "Idempotency key: the same key with the same payload replays the\nSAME stored result (never double-applies); the same key with a\ndifferent payload is a typed 409. Generate one per user edit\ndebounce/retry episode (UUID works).",
            "type": [
              "string",
              "null"
            ]
          },
          "version": {
            "description": "If-Match-style version: the entity `version` the caller last saw\n(the `mutation.version` of the previous response). A mismatch\nrejects the write with a typed 409 `version_conflict` carrying\n`expected`/`provided`; omit for creates and for legacy callers.",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "MyWorkItem": {
        "description": "One cross-board my-work queue row (TASKLIST 2.11): the ticket plus the\nannotations the Today screen renders per the mockup.",
        "properties": {
          "board_id": {
            "description": "The source board of this cross-board row.",
            "format": "uuid",
            "type": "string"
          },
          "board_name": {
            "type": "string"
          },
          "category": {
            "$ref": "#/components/schemas/TicketStatusCategory"
          },
          "client_name": {
            "description": "Client short label for the squared tag (`None` = internal ticket).",
            "type": [
              "string",
              "null"
            ]
          },
          "due_at": {
            "description": "Manual deadline set on the ticket itself.",
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "number": {
            "type": "string"
          },
          "priority": {
            "$ref": "#/components/schemas/Priority"
          },
          "sla_resolution_due": {
            "description": "SLA resolution deadline when state exists; the UI prefers this over\n`due_at` for the right-aligned countdown column.",
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "status_name": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "id",
          "number",
          "title",
          "priority",
          "category",
          "status_name",
          "board_id",
          "board_name",
          "updated_at"
        ],
        "type": "object"
      },
      "NoteKind": {
        "description": "Taxonomy of structured ticket notes (§1).",
        "enum": [
          "internal",
          "client_visible",
          "in_house_update"
        ],
        "type": "string"
      },
      "Notification": {
        "properties": {
          "body": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "kind": {
            "$ref": "#/components/schemas/NotificationKind"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "read_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "ticket_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "title": {
            "type": "string"
          },
          "user_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "user_id",
          "kind",
          "title",
          "created_at"
        ],
        "type": "object"
      },
      "NotificationKind": {
        "enum": [
          "mention",
          "assignment",
          "sla_risk",
          "sla_breach",
          "escalation",
          "missing_time",
          "ticket_update",
          "report_delivery"
        ],
        "type": "string"
      },
      "NotificationPage": {
        "description": "One page of the inbox plus the cursor to continue with.",
        "properties": {
          "items": {
            "items": {
              "$ref": "#/components/schemas/Notification"
            },
            "type": "array"
          },
          "next_cursor": {
            "description": "Pass as `cursor` on the next request; `None` means exhausted.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "items"
        ],
        "type": "object"
      },
      "OidcProviderInfo": {
        "properties": {
          "client_id": {
            "type": "string"
          },
          "discovery_url": {
            "type": "string"
          },
          "display_name": {
            "type": "string"
          },
          "enabled": {
            "type": "boolean"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "issuer": {
            "type": "string"
          },
          "jit_provisioning": {
            "type": "boolean"
          },
          "name": {
            "description": "URL path segment used by login/link routes.",
            "type": "string"
          }
        },
        "required": [
          "id",
          "name",
          "display_name",
          "issuer",
          "discovery_url",
          "client_id",
          "jit_provisioning",
          "enabled"
        ],
        "type": "object"
      },
      "OnCallBlock": {
        "description": "An absolute UTC on-call rotation segment for one user.",
        "properties": {
          "category": {
            "description": "Free-form rotation label ('primary', 'secondary', 'escalation', …).",
            "type": "string"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "ends_at": {
            "format": "date-time",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "starts_at": {
            "format": "date-time",
            "type": "string"
          },
          "user_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "user_id",
          "starts_at",
          "ends_at",
          "category",
          "created_at"
        ],
        "type": "object"
      },
      "OrgBillingPreview": {
        "description": "Org-wide preview: every billable contract's evaluation for the window\nplus the grand total — the shape a Wave-9 invoice run will consume.",
        "properties": {
          "evaluations": {
            "items": {
              "$ref": "#/components/schemas/BillingEvaluation"
            },
            "type": "array"
          },
          "from": {
            "format": "date",
            "type": "string"
          },
          "to": {
            "format": "date",
            "type": "string"
          },
          "total_minor": {
            "description": "Sum over evaluations, minor units (mixed currencies reject).",
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "from",
          "to",
          "evaluations",
          "total_minor"
        ],
        "type": "object"
      },
      "OrgProfileResponse": {
        "properties": {
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "ticket_prefix": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "name",
          "slug",
          "ticket_prefix"
        ],
        "type": "object"
      },
      "OwnedDeleteQuery": {
        "properties": {
          "user_id": {
            "description": "Owner of the row being deleted (must match self-or-admin rule).",
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "user_id"
        ],
        "type": "object"
      },
      "PatchAlertSourceRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1): idempotency key + entity\nversion. Absent in legacy clients — purely additive."
          },
          {
            "properties": {
              "board_id": {
                "format": "uuid",
                "type": [
                  "string",
                  "null"
                ]
              },
              "client_id": {
                "description": "`Some(None)` clears; `Some(Some(v))` sets; `None` = no change.",
                "format": "uuid",
                "type": [
                  "string",
                  "null"
                ]
              },
              "correlation_window_secs": {
                "format": "int32",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "enabled": {
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "name": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "type": "object"
          }
        ]
      },
      "PatchAppointmentRequest": {
        "properties": {
          "kind": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/AppointmentKind"
              }
            ]
          },
          "notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/AppointmentStatus"
              }
            ]
          },
          "ticket_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "title": {
            "type": [
              "string",
              "null"
            ]
          },
          "travel_minutes": {
            "format": "int32",
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "PatchContractRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1): idempotency key +\nIf-Match `version`. Absent in legacy clients — purely additive."
          },
          {
            "properties": {
              "amount_minor": {
                "format": "int64",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "billing_anchor": {
                "format": "date",
                "type": [
                  "string",
                  "null"
                ]
              },
              "billing_frequency": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/BillingFrequency"
                  }
                ]
              },
              "client_id": {
                "format": "uuid",
                "type": [
                  "string",
                  "null"
                ]
              },
              "contract_type": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/ContractType"
                  }
                ]
              },
              "currency": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "effective_from": {
                "format": "date",
                "type": [
                  "string",
                  "null"
                ]
              },
              "effective_until": {
                "format": "date",
                "type": [
                  "string",
                  "null"
                ]
              },
              "fees": {
                "description": "When present, replaces the whole fee schedule.",
                "items": {
                  "$ref": "#/components/schemas/FeeSpec"
                },
                "type": [
                  "array",
                  "null"
                ]
              },
              "hourly_rate_minor": {
                "format": "int64",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "included_minutes": {
                "format": "int32",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "name": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "notes": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "number": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "overage_rate_minor": {
                "format": "int64",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "rates": {
                "description": "When present, replaces the whole rate card.",
                "items": {
                  "$ref": "#/components/schemas/RateSpec"
                },
                "type": [
                  "array",
                  "null"
                ]
              },
              "status": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/ContractStatus"
                  }
                ]
              }
            },
            "type": "object"
          }
        ]
      },
      "PatchOrgRequest": {
        "properties": {
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "ticket_prefix": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "PatchPhaseRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1): idempotency key + entity\nversion. Absent in legacy clients — purely additive."
          },
          {
            "properties": {
              "description": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "is_milestone": {
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "milestone_amount_minor": {
                "format": "int64",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "milestone_currency": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "name": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "sort_order": {
                "format": "int32",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "status": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/PhaseStatus"
                  }
                ]
              }
            },
            "type": "object"
          }
        ]
      },
      "PatchPortalUserRequest": {
        "properties": {
          "display_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "password": {
            "description": "Optional credential reset (hashed before storage).",
            "type": [
              "string",
              "null"
            ]
          },
          "role": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/PortalRole"
              }
            ]
          },
          "status": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/PortalUserStatus",
                "description": "`disabled` blocks login AND every authenticated request immediately."
              }
            ]
          }
        },
        "type": "object"
      },
      "PatchProjectRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1): idempotency key + entity\nversion. Absent in legacy clients — purely additive."
          },
          {
            "properties": {
              "billing_method": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/BillingMethod"
                  }
                ]
              },
              "budget_minor": {
                "format": "int64",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "client_id": {
                "format": "uuid",
                "type": [
                  "string",
                  "null"
                ]
              },
              "currency": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "description": {
                "description": "`Some(Some(v))` sets; `Some(None)` clears; `None` = no change.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "due_date": {
                "format": "date",
                "type": [
                  "string",
                  "null"
                ]
              },
              "name": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "start_date": {
                "format": "date",
                "type": [
                  "string",
                  "null"
                ]
              },
              "status": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/ProjectStatus"
                  }
                ]
              }
            },
            "type": "object"
          }
        ]
      },
      "PatchTaskRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1): idempotency key + entity\nversion. Absent in legacy clients — purely additive."
          },
          {
            "properties": {
              "assignee_id": {
                "format": "uuid",
                "type": [
                  "string",
                  "null"
                ]
              },
              "description": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "due_at": {
                "format": "date-time",
                "type": [
                  "string",
                  "null"
                ]
              },
              "is_milestone": {
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "milestone_amount_minor": {
                "format": "int64",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "milestone_currency": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "phase_id": {
                "format": "uuid",
                "type": [
                  "string",
                  "null"
                ]
              },
              "sort_order": {
                "format": "int32",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "status": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/TaskStatus",
                    "description": "Lifecycle moves other than completion (pending / in_progress /\nblocked / cancelled). Reaching `completed` MUST go through the\ncomplete endpoint so dependency gating + billing events cannot be\nskipped."
                  }
                ]
              },
              "title": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "type": "object"
          }
        ]
      },
      "PatchTemplateRequest": {
        "properties": {
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "spec": {}
        },
        "type": "object"
      },
      "PatchTicketRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1): idempotency key + entity\nversion. Absent in legacy clients — purely additive."
          },
          {
            "properties": {
              "assignee_id": {
                "description": "`Some(Some(id))` assigns; `Some(None)` unassigns; `None` = no change.",
                "format": "uuid",
                "type": [
                  "string",
                  "null"
                ]
              },
              "body": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "client_id": {
                "format": "uuid",
                "type": [
                  "string",
                  "null"
                ]
              },
              "contact_id": {
                "format": "uuid",
                "type": [
                  "string",
                  "null"
                ]
              },
              "custom_fields": {
                "description": "Custom-field values to upsert. Partial semantics: only listed fields\nchange, each validated against its definition.",
                "items": {
                  "$ref": "#/components/schemas/TicketFieldInput"
                },
                "type": [
                  "array",
                  "null"
                ]
              },
              "due_at": {
                "format": "date-time",
                "type": [
                  "string",
                  "null"
                ]
              },
              "priority": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/Priority"
                  }
                ]
              },
              "site_id": {
                "format": "uuid",
                "type": [
                  "string",
                  "null"
                ]
              },
              "title": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "type": "object"
          }
        ]
      },
      "PatchTravelDraftRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams"
          },
          {
            "properties": {
              "billable": {
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "distance": {
                "format": "double",
                "type": [
                  "number",
                  "null"
                ]
              },
              "distance_unit": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "ended_at": {
                "format": "date-time",
                "type": [
                  "string",
                  "null"
                ]
              },
              "notes": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "started_at": {
                "format": "date-time",
                "type": [
                  "string",
                  "null"
                ]
              },
              "ticket_id": {
                "format": "uuid",
                "type": [
                  "string",
                  "null"
                ]
              },
              "user_id": {
                "format": "uuid",
                "type": [
                  "string",
                  "null"
                ]
              },
              "vehicle": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "type": "object"
          }
        ],
        "description": "PATCH /api/dispatch/travel-drafts/{id} body — every member optional;\nabsent members are left untouched."
      },
      "PatchViewRequest": {
        "properties": {
          "is_default": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "spec": {}
        },
        "type": "object"
      },
      "PauseTimerRequest": {
        "properties": {
          "reason": {
            "description": "Optional reason, preserved on the segment forever.",
            "type": [
              "string",
              "null"
            ]
          },
          "session_id": {
            "description": "Omit to act on the caller's active timer.",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "PaymentMutationResponse": {
        "description": "Payment receipt response. The invoice is nested (not flattened) so\nthe stored replay payload — `{payment, invoice}` plus the merged\nmutation metadata — deserializes into this shape byte-identically.",
        "properties": {
          "invoice": {
            "$ref": "#/components/schemas/Invoice"
          },
          "mutation": {
            "$ref": "#/components/schemas/MutationMeta"
          },
          "payment": {
            "$ref": "#/components/schemas/InvoicePayment"
          }
        },
        "required": [
          "payment",
          "invoice",
          "mutation"
        ],
        "type": "object"
      },
      "PhaseMutationResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ProjectPhase"
          },
          {
            "properties": {
              "mutation": {
                "$ref": "#/components/schemas/MutationMeta"
              }
            },
            "required": [
              "mutation"
            ],
            "type": "object"
          }
        ]
      },
      "PhaseStatus": {
        "description": "Lifecycle of a phase.",
        "enum": [
          "pending",
          "active",
          "completed",
          "cancelled"
        ],
        "type": "string"
      },
      "PolicyView": {
        "properties": {
          "calendar_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "is_default": {
            "type": "boolean"
          },
          "name": {
            "type": "string"
          },
          "targets": {
            "description": "Targets keyed by priority (\"p1\"..\"p4\"), business minutes."
          },
          "uses_embedded_calendar": {
            "description": "True while the policy governs itself via its embedded calendar.",
            "type": "boolean"
          }
        },
        "required": [
          "id",
          "name",
          "is_default",
          "targets",
          "uses_embedded_calendar"
        ],
        "type": "object"
      },
      "PortalAppointmentRequestMutationResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/AppointmentRequest"
          },
          {
            "properties": {
              "mutation": {
                "$ref": "#/components/schemas/MutationMeta"
              }
            },
            "required": [
              "mutation"
            ],
            "type": "object"
          }
        ],
        "description": "Instant-first mutation response (IF2) for appointment-request writes.\nThe request fields sit at the TOP LEVEL (flattened) so the stored\nreplay payload (`request` serialized + merged mutation metadata)\nround-trips byte-identically."
      },
      "PortalArticleListQuery": {
        "properties": {
          "category_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "limit": {
            "format": "int64",
            "type": "integer"
          },
          "offset": {
            "format": "int64",
            "type": "integer"
          }
        },
        "type": "object"
      },
      "PortalAttachmentView": {
        "description": "Portal attachment view: metadata only (bytes stream on download).",
        "properties": {
          "content_type": {
            "type": "string"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "filename": {
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "sha256": {
            "type": "string"
          },
          "size_bytes": {
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "id",
          "filename",
          "content_type",
          "size_bytes",
          "sha256",
          "created_at"
        ],
        "type": "object"
      },
      "PortalCancelRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1)."
          }
        ],
        "description": "Body for the portal cancel (idempotency parameters only)."
      },
      "PortalCreateAppointmentRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1): idempotency key."
          },
          {
            "properties": {
              "ends_at": {
                "format": "date-time",
                "type": "string"
              },
              "kind": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/AppointmentKind",
                    "description": "`on_site | remote` (internal/personal are staff-only kinds)."
                  }
                ]
              },
              "notes": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "starts_at": {
                "format": "date-time",
                "type": "string"
              },
              "title": {
                "type": "string"
              },
              "user_id": {
                "description": "The staff member whose calendar the client asked for.",
                "format": "uuid",
                "type": "string"
              }
            },
            "required": [
              "user_id",
              "title",
              "starts_at",
              "ends_at"
            ],
            "type": "object"
          }
        ]
      },
      "PortalInvoice": {
        "description": "The client-facing invoice document view. Deliberately NOT the staff\nentity: dunning internals and staff notes never reach the portal.",
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "currency": {
            "type": "string"
          },
          "due_on": {
            "format": "date",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "issued_at": {
            "format": "date",
            "type": "string"
          },
          "number": {
            "type": "string"
          },
          "outstanding_minor": {
            "description": "`total_minor - total_paid_minor`, never negative.",
            "format": "int64",
            "type": "integer"
          },
          "period_from": {
            "format": "date",
            "type": [
              "string",
              "null"
            ]
          },
          "period_to": {
            "format": "date",
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "description": "`issued | paid` (void/draft documents are staff-internal).",
            "type": "string"
          },
          "total_minor": {
            "format": "int64",
            "type": "integer"
          },
          "total_paid_minor": {
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "id",
          "number",
          "status",
          "currency",
          "issued_at",
          "due_on",
          "total_minor",
          "total_paid_minor",
          "outstanding_minor",
          "created_at"
        ],
        "type": "object"
      },
      "PortalInvoiceDetail": {
        "description": "The client-facing invoice aggregate.",
        "properties": {
          "invoice": {
            "$ref": "#/components/schemas/PortalInvoice"
          },
          "lines": {
            "items": {
              "$ref": "#/components/schemas/InvoiceLine"
            },
            "type": "array"
          },
          "payments": {
            "items": {
              "$ref": "#/components/schemas/PortalPaymentView"
            },
            "type": "array"
          }
        },
        "required": [
          "invoice",
          "lines",
          "payments"
        ],
        "type": "object"
      },
      "PortalKbSearchHit": {
        "properties": {
          "article": {
            "$ref": "#/components/schemas/KbArticle"
          },
          "score": {
            "description": "FTS rank blended with trigram similarity — ordering signal only.",
            "format": "double",
            "type": "number"
          }
        },
        "required": [
          "article",
          "score"
        ],
        "type": "object"
      },
      "PortalKbSearchQuery": {
        "properties": {
          "limit": {
            "format": "int64",
            "type": "integer"
          },
          "offset": {
            "format": "int64",
            "type": "integer"
          },
          "q": {
            "description": "Websearch query (plain words, quoted phrases, `OR`, `-`\nexclusions — Postgres websearch syntax).",
            "type": "string"
          }
        },
        "required": [
          "q"
        ],
        "type": "object"
      },
      "PortalLoginRequest": {
        "properties": {
          "email": {
            "type": "string"
          },
          "password": {
            "type": "string"
          }
        },
        "required": [
          "email",
          "password"
        ],
        "type": "object"
      },
      "PortalLoginResponse": {
        "properties": {
          "access_token": {
            "type": "string"
          },
          "expires_in": {
            "format": "int64",
            "type": "integer"
          },
          "portal_user": {
            "$ref": "#/components/schemas/PortalProfile"
          },
          "refresh_token": {
            "type": "string"
          },
          "session_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "access_token",
          "refresh_token",
          "session_id",
          "expires_in",
          "portal_user"
        ],
        "type": "object"
      },
      "PortalPayRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1): idempotency key + If-Match\n`version` on the invoice."
          },
          {
            "properties": {
              "amount_minor": {
                "description": "Amount to settle, minor units; must not exceed the outstanding\nbalance. Currency is always the invoice's own.",
                "format": "int64",
                "type": "integer"
              },
              "notes": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "amount_minor"
            ],
            "type": "object"
          }
        ]
      },
      "PortalPayResponse": {
        "description": "Instant-first mutation response (IF2) for a portal payment: the\nreceipt, the refreshed client-facing invoice, and the additive\n`mutation` metadata. Stored/replayed byte-identically under the key.",
        "properties": {
          "invoice": {
            "$ref": "#/components/schemas/PortalInvoice"
          },
          "mutation": {
            "$ref": "#/components/schemas/MutationMeta"
          },
          "payment": {
            "$ref": "#/components/schemas/InvoicePayment"
          }
        },
        "required": [
          "payment",
          "invoice",
          "mutation"
        ],
        "type": "object"
      },
      "PortalPaymentView": {
        "description": "A payment receipt as the portal sees it. `created_by` stays internal\n(portal identities are not staff rows; the field is always NULL on\nportal-recorded rows anyway).",
        "properties": {
          "amount_minor": {
            "format": "int64",
            "type": "integer"
          },
          "currency": {
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "provider": {
            "description": "`'none'` while no external PSP is connected — the receipt is a\nledger entry, not a card charge.",
            "type": "string"
          },
          "received_at": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "id",
          "amount_minor",
          "currency",
          "provider",
          "received_at"
        ],
        "type": "object"
      },
      "PortalProfile": {
        "description": "The signed-in portal identity (also served by GET /api/portal/me).",
        "properties": {
          "client_id": {
            "format": "uuid",
            "type": "string"
          },
          "display_name": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "role": {
            "$ref": "#/components/schemas/PortalRole"
          }
        },
        "required": [
          "id",
          "org_id",
          "client_id",
          "email",
          "display_name",
          "role"
        ],
        "type": "object"
      },
      "PortalRefreshRequest": {
        "properties": {
          "refresh_token": {
            "type": "string"
          },
          "session_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "refresh_token",
          "session_id"
        ],
        "type": "object"
      },
      "PortalReplyRequest": {
        "properties": {
          "body": {
            "type": "string"
          }
        },
        "required": [
          "body"
        ],
        "type": "object"
      },
      "PortalRole": {
        "description": "Portal role tiers. `contact` is the default read/reply tier;\n`approver` is behaviorally identical in v1 but exists so approval\ngrants (Stage 3 quote approval / Stage 4 optional client approvals)\ncan be layered on without re-provisioning identities; `it_manager`\nADDITIONALLY reads `in_house_update` notes. NO tier ever reads\n`internal` notes — enforced by `notes::visible_kinds`, tested in\n`policy` and `notes`.",
        "enum": [
          "contact",
          "approver",
          "it_manager"
        ],
        "type": "string"
      },
      "PortalSlotInterval": {
        "description": "Free intervals for one staff member over the query range.",
        "properties": {
          "ends_at": {
            "format": "date-time",
            "type": "string"
          },
          "starts_at": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "starts_at",
          "ends_at"
        ],
        "type": "object"
      },
      "PortalSlotsQuery": {
        "properties": {
          "from": {
            "description": "Range start (inclusive), ISO date.",
            "format": "date",
            "type": "string"
          },
          "to": {
            "description": "Range end (inclusive), ISO date.",
            "format": "date",
            "type": "string"
          },
          "user_id": {
            "description": "Optional: narrow to one staff member.",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "from",
          "to"
        ],
        "type": "object"
      },
      "PortalStaffSlots": {
        "description": "One staff member's published free slots over the query range.",
        "properties": {
          "display_name": {
            "type": "string"
          },
          "slots": {
            "description": "Sorted, internally disjoint, contiguous FREE stretches. A client\nrequests a slice of one; the server re-validates at request time\nand again at approval.",
            "items": {
              "$ref": "#/components/schemas/PortalSlotInterval"
            },
            "type": "array"
          },
          "user_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "user_id",
          "display_name",
          "slots"
        ],
        "type": "object"
      },
      "PortalTicketDetail": {
        "properties": {
          "can_view_in_house_updates": {
            "type": "boolean"
          },
          "comments": {
            "description": "Only the kinds this tier may read, filtered by the domain policy.",
            "items": {
              "$ref": "#/components/schemas/TicketComment"
            },
            "type": "array"
          },
          "ticket": {
            "$ref": "#/components/schemas/Ticket"
          }
        },
        "required": [
          "ticket",
          "comments",
          "can_view_in_house_updates"
        ],
        "type": "object"
      },
      "PortalTicketListQuery": {
        "properties": {
          "board_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "category": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/TicketStatusCategory"
              }
            ]
          },
          "limit": {
            "format": "int64",
            "type": "integer"
          },
          "offset": {
            "format": "int64",
            "type": "integer"
          }
        },
        "type": "object"
      },
      "PortalUser": {
        "properties": {
          "client_id": {
            "format": "uuid",
            "type": "string"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "display_name": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "role": {
            "$ref": "#/components/schemas/PortalRole"
          },
          "status": {
            "$ref": "#/components/schemas/PortalUserStatus"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "client_id",
          "email",
          "display_name",
          "role",
          "status",
          "created_at",
          "updated_at"
        ],
        "type": "object"
      },
      "PortalUserStatus": {
        "description": "Lifecycle of a portal identity. `invited` = admin-provisioned, has not\nlogged in yet; first successful login flips to `active`. `disabled`\nblocks login AND every authenticated portal request (checked per\nrequest, never cached in the token).",
        "enum": [
          "invited",
          "active",
          "disabled"
        ],
        "type": "string"
      },
      "PreferenceView": {
        "description": "One resolved preference row: which chain link supplied it (`user`,\n`org_default`, or `builtin`), the channel toggles, and the quiet-hours\nwindow with its timezone.",
        "properties": {
          "email": {
            "type": "boolean"
          },
          "in_app": {
            "type": "boolean"
          },
          "kind": {
            "$ref": "#/components/schemas/NotificationKind"
          },
          "quiet_from": {
            "type": [
              "string",
              "null"
            ]
          },
          "quiet_until": {
            "type": [
              "string",
              "null"
            ]
          },
          "source": {
            "type": "string"
          },
          "timezone": {
            "type": "string"
          }
        },
        "required": [
          "kind",
          "source",
          "in_app",
          "email",
          "timezone"
        ],
        "type": "object"
      },
      "PreviewQuery": {
        "properties": {
          "from": {
            "description": "Window start (inclusive), ISO date.",
            "format": "date",
            "type": [
              "string",
              "null"
            ]
          },
          "to": {
            "description": "Window end (inclusive), ISO date.",
            "format": "date",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "Priority": {
        "description": "Industry-standard four-tier priority.",
        "enum": [
          "p1",
          "p2",
          "p3",
          "p4"
        ],
        "type": "string"
      },
      "Project": {
        "description": "A project engagement under a client (or internal when `client_id` is\n`None`).",
        "properties": {
          "billing_method": {
            "$ref": "#/components/schemas/BillingMethod"
          },
          "budget_minor": {
            "description": "Project budget in minor units; `None` = unbudgeted.",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "client_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "currency": {
            "description": "ISO 4217 currency for `budget_minor` (required when a budget is set).",
            "type": [
              "string",
              "null"
            ]
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "due_date": {
            "format": "date",
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "start_date": {
            "format": "date",
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "$ref": "#/components/schemas/ProjectStatus"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "name",
          "status",
          "billing_method",
          "created_at",
          "updated_at"
        ],
        "type": "object"
      },
      "ProjectInstantiateResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Project"
          },
          {
            "properties": {
              "mutation": {
                "$ref": "#/components/schemas/MutationMeta"
              },
              "phase_count": {
                "format": "int64",
                "type": "integer"
              },
              "task_count": {
                "format": "int64",
                "type": "integer"
              }
            },
            "required": [
              "phase_count",
              "task_count",
              "mutation"
            ],
            "type": "object"
          }
        ],
        "description": "The instantiation result: the applied project plus the expansion\ncounts (clients render \"created N phases, M tasks\" without refetching)."
      },
      "ProjectListQuery": {
        "properties": {
          "client_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "limit": {
            "format": "int64",
            "type": "integer"
          },
          "offset": {
            "format": "int64",
            "type": "integer"
          },
          "status": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/ProjectStatus"
              }
            ]
          }
        },
        "type": "object"
      },
      "ProjectMutationResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Project"
          },
          {
            "properties": {
              "mutation": {
                "$ref": "#/components/schemas/MutationMeta"
              }
            },
            "required": [
              "mutation"
            ],
            "type": "object"
          }
        ],
        "description": "Instant-first mutation response for the project entity (IF2): applied\nsnapshot at the top level plus the additive `mutation` metadata."
      },
      "ProjectPhase": {
        "description": "A phase groups tasks into a delivery stage. A phase flagged\n`is_milestone` is itself a billing milestone.",
        "properties": {
          "completed_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "is_milestone": {
            "type": "boolean"
          },
          "milestone_amount_minor": {
            "description": "Billing amount released when this milestone phase completes\n(minor units; `None` = informational milestone).",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "milestone_currency": {
            "description": "ISO 4217 code for `milestone_amount_minor`.",
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "project_id": {
            "format": "uuid",
            "type": "string"
          },
          "sort_order": {
            "format": "int32",
            "type": "integer"
          },
          "status": {
            "$ref": "#/components/schemas/PhaseStatus"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "project_id",
          "name",
          "sort_order",
          "status",
          "is_milestone",
          "created_at",
          "updated_at"
        ],
        "type": "object"
      },
      "ProjectStatus": {
        "description": "Lifecycle of a project.",
        "enum": [
          "planning",
          "active",
          "on_hold",
          "completed",
          "cancelled"
        ],
        "type": "string"
      },
      "ProjectTask": {
        "description": "A unit of project work. A task flagged `is_milestone` is a billing\nmilestone: completing it emits `project.milestone_completed`.",
        "properties": {
          "assignee_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "completed_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "due_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "is_milestone": {
            "type": "boolean"
          },
          "milestone_amount_minor": {
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "milestone_currency": {
            "type": [
              "string",
              "null"
            ]
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "phase_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "project_id": {
            "format": "uuid",
            "type": "string"
          },
          "sort_order": {
            "format": "int32",
            "type": "integer"
          },
          "status": {
            "$ref": "#/components/schemas/TaskStatus"
          },
          "title": {
            "type": "string"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "project_id",
          "title",
          "status",
          "sort_order",
          "is_milestone",
          "created_at",
          "updated_at"
        ],
        "type": "object"
      },
      "ProjectTemplate": {
        "description": "A reusable project blueprint. `spec` follows `core-projects::template`\n(`TemplateSpec`, additive-only evolution); instantiation is a plain\ntransactional insert plan — templates are data, not code (policy §5).",
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "spec": {
            "type": "object"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "name",
          "spec",
          "created_at",
          "updated_at"
        ],
        "type": "object"
      },
      "ProjectView": {
        "description": "A saved task-list view: filter/group/sort spec over one project's tasks\n(`project_id: None` = org-wide). The `spec` is a versioned, additive-only\nJSON document validated at the route layer; unknown fields are tolerated\n(policy §2 posture for declared customizations-as-data).",
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "is_default": {
            "type": "boolean"
          },
          "name": {
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "project_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "spec": {
            "type": "object"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "name",
          "spec",
          "is_default",
          "created_at",
          "updated_at"
        ],
        "type": "object"
      },
      "ProposalClassification": {
        "description": "Proposal classification: who will see the change if it lands.",
        "enum": [
          "internal",
          "client_visible",
          "external_commit"
        ],
        "type": "string"
      },
      "ProposalListQuery": {
        "description": "GET /api/agent-proposals query.",
        "properties": {
          "cursor": {
            "description": "Opaque keyset cursor from a previous page's `next_cursor`.",
            "type": [
              "string",
              "null"
            ]
          },
          "limit": {
            "description": "Page size, clamped to [1, 200].",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "status": {
            "description": "Filter by lifecycle state.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "ProposalStatus": {
        "description": "Proposal lifecycle state.",
        "enum": [
          "proposed",
          "approved",
          "declined",
          "withdrawn",
          "applied"
        ],
        "type": "string"
      },
      "ProvenanceEvent": {
        "description": "One provenance entry: a single field change within one applied write.",
        "properties": {
          "actor_id": {
            "description": "The acting user (or machine actor) id, when attributed.",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "actor_kind": {
            "description": "Actor kind from the write-trail vocabulary (human, agent, ...).",
            "type": "string"
          },
          "after": {
            "description": "Applied value; null when the field was removed in this write.",
            "type": [
              "object",
              "null"
            ]
          },
          "before": {
            "description": "Prior value; null when the field is new.",
            "type": [
              "object",
              "null"
            ]
          },
          "entity": {
            "description": "Entity family, e.g. \"ticket\".",
            "type": "string"
          },
          "entity_id": {
            "format": "uuid",
            "type": "string"
          },
          "field": {
            "description": "The changed field.",
            "type": "string"
          },
          "idempotency_key": {
            "description": "The idempotency key that claimed the write, when the caller\nsupplied one.",
            "type": [
              "string",
              "null"
            ]
          },
          "occurred_at": {
            "type": "string"
          },
          "op": {
            "description": "Machine-readable operation (\"create\", \"update\", \"status_change\", ...).",
            "type": "string"
          },
          "ruleset_hash": {
            "description": "Rule-set hash that governed the write, when present.",
            "type": [
              "string",
              "null"
            ]
          },
          "seq": {
            "description": "The write's per-entity sequence (mirrors `mutation.version`).",
            "format": "int64",
            "type": "integer"
          },
          "session_id": {
            "description": "Agent session, when present (IF8-approved writes).",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "skill": {
            "description": "Skill that authored the write, when present.",
            "type": [
              "string",
              "null"
            ]
          },
          "undo": {
            "description": "True for undo reverts (IF7) riding the normal write path.",
            "type": "boolean"
          },
          "write_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "write_id",
          "entity",
          "entity_id",
          "seq",
          "op",
          "actor_kind",
          "actor_id",
          "field",
          "before",
          "after",
          "undo",
          "occurred_at"
        ],
        "type": "object"
      },
      "ProvenancePage": {
        "properties": {
          "events": {
            "items": {
              "$ref": "#/components/schemas/ProvenanceEvent"
            },
            "type": "array"
          },
          "next_cursor": {
            "description": "Opaque cursor for the next page; absent when exhausted.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "events"
        ],
        "type": "object"
      },
      "PublicProvider": {
        "properties": {
          "display_name": {
            "type": "string"
          },
          "name": {
            "description": "URL path segment for /api/auth/oidc/{name}/login.",
            "type": "string"
          }
        },
        "required": [
          "name",
          "display_name"
        ],
        "type": "object"
      },
      "PublishSkillRequest": {
        "properties": {
          "manifest": {
            "description": "`{capabilities: [...], prompts: [...], rules: [...]}`.",
            "type": "object"
          },
          "slug": {
            "description": "Slug; version is derived server-side (max + 1) — append-only\nhistory, never an in-place edit.",
            "type": "string"
          }
        },
        "required": [
          "slug",
          "manifest"
        ],
        "type": "object"
      },
      "PullItem": {
        "description": "One exported row: internal id, stable source key when the row was ever\npushed under one, and the canonical projection (the SAME field catalog\nthe push side diffs against).",
        "properties": {
          "external_key": {
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "projection": {
            "type": "object"
          }
        },
        "required": [
          "id",
          "projection"
        ],
        "type": "object"
      },
      "PullPage": {
        "description": "GET /api/migration/pull/{family} envelope.",
        "properties": {
          "family": {
            "$ref": "#/components/schemas/EntityKind"
          },
          "items": {
            "items": {
              "$ref": "#/components/schemas/PullItem"
            },
            "type": "array"
          },
          "next_cursor": {
            "description": "Pass back as `cursor`; absent when exhausted.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "family",
          "items"
        ],
        "type": "object"
      },
      "PullQuery": {
        "description": "GET /api/migration/pull/{family} query.",
        "properties": {
          "cursor": {
            "description": "Opaque keyset cursor from a previous page's `next_cursor` (the last\nrow id). Absent = start of the family.",
            "type": [
              "string",
              "null"
            ]
          },
          "limit": {
            "description": "Page size, clamped to [1, 200] (default 100).",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "PushCheckpoint": {
        "description": "The checkpoint cursor of a push session: what the server has committed\nand what it expects next. `last_committed_chunk` is `-1` on a fresh\nsession.",
        "properties": {
          "last_committed_chunk": {
            "description": "Highest committed chunk index; -1 before the first chunk.",
            "format": "int64",
            "type": "integer"
          },
          "next_chunk": {
            "description": "The chunk index the next POST must carry.",
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "last_committed_chunk",
          "next_chunk"
        ],
        "type": "object"
      },
      "PushChunkReport": {
        "description": "The per-row report of one chunk — the D2 contract shape, kept\nSerialize+Deserialize so a committed chunk's stored copy replays\nfaithfully on an exact re-send.",
        "properties": {
          "batch_id": {
            "format": "uuid",
            "type": "string"
          },
          "conflict_policy": {
            "$ref": "#/components/schemas/ConflictPolicy"
          },
          "dry_run": {
            "type": "boolean"
          },
          "entity_kind": {
            "$ref": "#/components/schemas/EntityKind"
          },
          "rows": {
            "items": {
              "$ref": "#/components/schemas/RowReport"
            },
            "type": "array"
          },
          "summary": {
            "$ref": "#/components/schemas/PushChunkSummary"
          }
        },
        "required": [
          "batch_id",
          "dry_run",
          "entity_kind",
          "conflict_policy",
          "summary",
          "rows"
        ],
        "type": "object"
      },
      "PushChunkRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/RowsPayload"
          },
          {
            "properties": {
              "chunk_index": {
                "description": "Position of this chunk in the run. Must be the checkpoint's\n`next_chunk`; a lower index replays (same payload) or 409s\n(`migration_chunk_reused`, different payload); a higher index 409s\n(`migration_cursor_mismatch`) — chunks are sequential.",
                "format": "int64",
                "type": "integer"
              }
            },
            "required": [
              "chunk_index"
            ],
            "type": "object"
          }
        ],
        "description": "POST /api/migration/push/sessions/{id}/chunks body."
      },
      "PushChunkResponse": {
        "properties": {
          "checkpoint": {
            "$ref": "#/components/schemas/PushCheckpoint"
          },
          "chunk_index": {
            "format": "int64",
            "type": "integer"
          },
          "replay": {
            "description": "`true` when an exact re-send replayed the stored report without\ntouching data (retry after a lost response is free).",
            "type": "boolean"
          },
          "report": {
            "$ref": "#/components/schemas/PushChunkReport"
          },
          "rows_created": {
            "format": "int64",
            "type": "integer"
          },
          "rows_failed": {
            "format": "int64",
            "type": "integer"
          },
          "rows_skipped": {
            "format": "int64",
            "type": "integer"
          },
          "rows_total": {
            "description": "Cumulative batch counters after this chunk.",
            "format": "int64",
            "type": "integer"
          },
          "rows_updated": {
            "format": "int64",
            "type": "integer"
          },
          "session_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "session_id",
          "chunk_index",
          "replay",
          "report",
          "checkpoint",
          "rows_total",
          "rows_created",
          "rows_updated",
          "rows_skipped",
          "rows_failed"
        ],
        "type": "object"
      },
      "PushChunkSummary": {
        "description": "u32-friendly mirror of the per-chunk summary so the generated SDK gets\nplain integers without overflow caveats (same shape as D2's\n`ChunkSummaryWire`, but also deserialize for replay).",
        "properties": {
          "failed": {
            "format": "int32",
            "minimum": 0,
            "type": "integer"
          },
          "ok": {
            "format": "int32",
            "minimum": 0,
            "type": "integer"
          },
          "total": {
            "format": "int32",
            "minimum": 0,
            "type": "integer"
          },
          "would_skip": {
            "format": "int32",
            "minimum": 0,
            "type": "integer"
          },
          "would_update": {
            "format": "int32",
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "total",
          "ok",
          "would_update",
          "would_skip",
          "failed"
        ],
        "type": "object"
      },
      "PushSessionCreated": {
        "description": "201 body: the session id, its D2 batch, and the starting cursor.",
        "properties": {
          "batch_id": {
            "format": "uuid",
            "type": "string"
          },
          "checkpoint": {
            "$ref": "#/components/schemas/PushCheckpoint"
          },
          "conflict_policy": {
            "$ref": "#/components/schemas/ConflictPolicy"
          },
          "entity_kind": {
            "$ref": "#/components/schemas/EntityKind"
          },
          "label": {
            "type": "string"
          },
          "session_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "session_id",
          "batch_id",
          "entity_kind",
          "conflict_policy",
          "label",
          "checkpoint"
        ],
        "type": "object"
      },
      "PushSessionFinishedResponse": {
        "description": "POST /api/migration/push/sessions/{id}/finish — closes the session and\nits D2 batch; returns the cumulative run totals.",
        "properties": {
          "batch_id": {
            "format": "uuid",
            "type": "string"
          },
          "checkpoint": {
            "$ref": "#/components/schemas/PushCheckpoint"
          },
          "chunks_committed": {
            "format": "int64",
            "type": "integer"
          },
          "conflict_policy": {
            "$ref": "#/components/schemas/ConflictPolicy"
          },
          "entity_kind": {
            "$ref": "#/components/schemas/EntityKind"
          },
          "rows_created": {
            "format": "int32",
            "type": "integer"
          },
          "rows_failed": {
            "format": "int32",
            "type": "integer"
          },
          "rows_skipped": {
            "format": "int32",
            "type": "integer"
          },
          "rows_total": {
            "format": "int32",
            "type": "integer"
          },
          "rows_updated": {
            "format": "int32",
            "type": "integer"
          },
          "session_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "session_id",
          "batch_id",
          "entity_kind",
          "conflict_policy",
          "chunks_committed",
          "rows_total",
          "rows_created",
          "rows_updated",
          "rows_skipped",
          "rows_failed",
          "checkpoint"
        ],
        "type": "object"
      },
      "PushSessionView": {
        "description": "GET /api/migration/push/sessions/{id} — the resume view a tool asks\nafter a crash: where the checkpoint stands and which chunks committed.",
        "properties": {
          "batch_id": {
            "format": "uuid",
            "type": "string"
          },
          "checkpoint": {
            "$ref": "#/components/schemas/PushCheckpoint"
          },
          "committed_chunks": {
            "items": {
              "$ref": "#/components/schemas/CommittedChunkRef"
            },
            "type": "array"
          },
          "conflict_policy": {
            "$ref": "#/components/schemas/ConflictPolicy"
          },
          "created_at": {
            "type": "string"
          },
          "entity_kind": {
            "$ref": "#/components/schemas/EntityKind"
          },
          "finished_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "label": {
            "type": "string"
          },
          "session_id": {
            "format": "uuid",
            "type": "string"
          },
          "source_note": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "session_id",
          "batch_id",
          "entity_kind",
          "conflict_policy",
          "label",
          "created_at",
          "checkpoint",
          "committed_chunks"
        ],
        "type": "object"
      },
      "PushStatusMutationResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/PushStatusResponse"
          },
          {
            "properties": {
              "mutation": {
                "$ref": "#/components/schemas/MutationMeta"
              }
            },
            "required": [
              "mutation"
            ],
            "type": "object"
          }
        ],
        "description": "201 body: the pushed row plus the read-your-write metadata (IF2)."
      },
      "PushStatusRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams"
          },
          {
            "properties": {
              "note": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "occurred_at": {
                "description": "When the status was observed; defaults to now (server clock).",
                "format": "date-time",
                "type": [
                  "string",
                  "null"
                ]
              },
              "status": {
                "description": "Field-service status: en_route | arrived | in_progress | completed\n| blocked | delayed.",
                "type": "string"
              }
            },
            "required": [
              "status"
            ],
            "type": "object"
          }
        ],
        "description": "POST /api/dispatch-connector/appointments/{id}/status body."
      },
      "PushStatusResponse": {
        "description": "The pushed row (entity fields; the mutation envelope flattens it).",
        "properties": {
          "appointment_id": {
            "format": "uuid",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "note": {
            "type": [
              "string",
              "null"
            ]
          },
          "occurred_at": {
            "format": "date-time",
            "type": "string"
          },
          "source": {
            "type": "string"
          },
          "status": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "appointment_id",
          "status",
          "source",
          "occurred_at"
        ],
        "type": "object"
      },
      "PutByokSecretRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1): idempotency key + entity\nversion. Absent in legacy clients — purely additive."
          },
          {
            "properties": {
              "api_key": {
                "description": "Plaintext API key / token to be sealed at rest.",
                "type": "string"
              },
              "provider": {
                "description": "Provider name: an AI provider (\"openai\", \"anthropic\", \"ollama\",\n\"custom\") or an export-sync connector (\"qbo\", \"xero\").",
                "type": "string"
              }
            },
            "required": [
              "provider",
              "api_key"
            ],
            "type": "object"
          }
        ],
        "description": "Request to store or update a sealed BYOK API key."
      },
      "PutCapabilityRequest": {
        "properties": {
          "capability": {
            "description": "`<namespace>:read` | `<namespace>:write`.",
            "type": "string"
          },
          "mode": {
            "$ref": "#/components/schemas/CapabilityMode"
          }
        },
        "required": [
          "capability",
          "mode"
        ],
        "type": "object"
      },
      "PutChecklistTemplateRequest": {
        "properties": {
          "items": {
            "description": "The complete required-step list; replaces any previous items.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "name": {
            "type": "string"
          },
          "require_checklist_close": {
            "description": "Enforcement toggle (defaults-first: OFF until explicitly enabled).",
            "type": "boolean"
          }
        },
        "required": [
          "name",
          "items"
        ],
        "type": "object"
      },
      "PutExposureRequest": {
        "properties": {
          "board_id": {
            "format": "uuid",
            "type": "string"
          },
          "exposed": {
            "type": "boolean"
          },
          "visible_status_ids": {
            "description": "Empty = all statuses visible (v1 default). Non-empty narrows to\nstatuses OF THAT BOARD — unknown ids are rejected, not silently kept.",
            "items": {
              "format": "uuid",
              "type": "string"
            },
            "type": "array"
          }
        },
        "required": [
          "board_id",
          "exposed",
          "visible_status_ids"
        ],
        "type": "object"
      },
      "QueueMutationResponse": {
        "description": "Queue mutation envelope (set + clear share the shape; clears carry\n`cleared: true` and null note).",
        "properties": {
          "cleared": {
            "type": "boolean"
          },
          "mutation": {
            "$ref": "#/components/schemas/MutationMeta"
          },
          "note": {
            "type": [
              "string",
              "null"
            ]
          },
          "rank": {
            "format": "int32",
            "type": "integer"
          },
          "ticket_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "ticket_id",
          "rank",
          "cleared",
          "mutation"
        ],
        "type": "object"
      },
      "QueuedTicket": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MyWorkItem"
          },
          {
            "properties": {
              "override_note": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "rank_override": {
                "description": "The dispatcher-set rank pinning this ticket's position (overrides\nsort ahead of the computed order); absent = computed order only.",
                "format": "int32",
                "type": [
                  "integer",
                  "null"
                ]
              }
            },
            "type": "object"
          }
        ],
        "description": "One queued ticket: the day-view's queue row shape plus the explicit\noverride when one exists."
      },
      "RangeParams": {
        "properties": {
          "from": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "to": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "user_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "RateSpec": {
        "description": "T&M rate-card row spec (hourly minor units per `work_type`).",
        "properties": {
          "rate_minor": {
            "format": "int64",
            "type": "integer"
          },
          "work_type": {
            "type": "string"
          }
        },
        "required": [
          "work_type",
          "rate_minor"
        ],
        "type": "object"
      },
      "RecordPaymentRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1): idempotency key +\nIf-Match `version` on the invoice."
          },
          {
            "properties": {
              "amount_minor": {
                "description": "Amount to collect, minor units; must not exceed the outstanding\nbalance. Currency is always the invoice's own.",
                "format": "int64",
                "type": "integer"
              },
              "notes": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "amount_minor"
            ],
            "type": "object"
          }
        ]
      },
      "RecoveryCodesResponse": {
        "properties": {
          "recovery_codes": {
            "description": "Plaintext codes — displayed once, stored only as argon2id hashes.",
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "required": [
          "recovery_codes"
        ],
        "type": "object"
      },
      "RefreshRequest": {
        "properties": {
          "refresh_token": {
            "type": "string"
          },
          "session_id": {
            "description": "Session id returned alongside the refresh token.",
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "refresh_token",
          "session_id"
        ],
        "type": "object"
      },
      "RegenerateRecoveryRequest": {
        "properties": {
          "code": {
            "type": "string"
          },
          "password": {
            "type": "string"
          }
        },
        "required": [
          "password",
          "code"
        ],
        "type": "object"
      },
      "RegisterRequest": {
        "properties": {
          "display_name": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "org_name": {
            "description": "Organization name — becomes the tenant for this deployment.",
            "type": "string"
          },
          "org_slug": {
            "description": "URL-safe org slug (unique).",
            "type": "string"
          },
          "password": {
            "type": "string"
          },
          "ticket_prefix": {
            "description": "Ticket number prefix, e.g. \"MER\" → MER-2841. Defaults to \"MER\".",
            "type": [
              "string",
              "null"
            ]
          },
          "timezone": {
            "default": "UTC",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "org_name",
          "org_slug",
          "email",
          "password",
          "display_name"
        ],
        "type": "object"
      },
      "RegistryResponse": {
        "properties": {
          "settings": {
            "items": {
              "$ref": "#/components/schemas/DeclarationView"
            },
            "type": "array"
          }
        },
        "required": [
          "settings"
        ],
        "type": "object"
      },
      "ReplaceLadderRequest": {
        "properties": {
          "steps": {
            "items": {
              "$ref": "#/components/schemas/LadderStepSpec"
            },
            "type": "array"
          }
        },
        "required": [
          "steps"
        ],
        "type": "object"
      },
      "ReplaceTicketSkillsRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams"
          },
          {
            "properties": {
              "skills": {
                "description": "Full replacement set (an empty set clears every requirement).",
                "items": {
                  "type": "string"
                },
                "type": "array"
              }
            },
            "required": [
              "skills"
            ],
            "type": "object"
          }
        ],
        "description": "PUT /api/dispatch/tickets/{ticket_id}/required-skills body."
      },
      "ReplaceUserSkillsRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams"
          },
          {
            "properties": {
              "skills": {
                "description": "Full replacement set (an empty set clears every skill).",
                "items": {
                  "$ref": "#/components/schemas/SkillInput"
                },
                "type": "array"
              }
            },
            "required": [
              "skills"
            ],
            "type": "object"
          }
        ],
        "description": "PUT /api/dispatch/users/{user_id}/skills body."
      },
      "ReportDefinitionList": {
        "description": "GET /api/report-definitions envelope.",
        "properties": {
          "definitions": {
            "items": {
              "$ref": "#/components/schemas/ReportDefinitionView"
            },
            "type": "array"
          }
        },
        "required": [
          "definitions"
        ],
        "type": "object"
      },
      "ReportDefinitionMutationResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ReportDefinitionView"
          },
          {
            "properties": {
              "mutation": {
                "$ref": "#/components/schemas/MutationMeta"
              }
            },
            "required": [
              "mutation"
            ],
            "type": "object"
          }
        ],
        "description": "Mutation envelope: applied definition (flattened) + read-your-write\nmetadata (IF2)."
      },
      "ReportDefinitionView": {
        "description": "A stored report definition with its registry-validated spec\nreassembled (`spec.view` == the stored `kind` column).",
        "properties": {
          "created_at": {
            "type": "string"
          },
          "created_by": {
            "format": "uuid",
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "scope": {
            "$ref": "#/components/schemas/DefinitionScope"
          },
          "spec": {
            "$ref": "#/components/schemas/ReportSpec"
          },
          "updated_at": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "name",
          "spec",
          "scope",
          "created_by",
          "created_at",
          "updated_at"
        ],
        "type": "object"
      },
      "ReportPage": {
        "description": "JSON envelope for a report page.",
        "properties": {
          "columns": {
            "description": "Stable column order (JSON objects here preserve insertion order via\nserde_json preserve_order feature transparently at runtime).",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "kind": {
            "type": "string"
          },
          "next_cursor": {
            "description": "Pass back as `cursor`; absent when exhausted or unpaged.",
            "type": [
              "string",
              "null"
            ]
          },
          "rows": {
            "items": {},
            "type": "array"
          },
          "summary": {
            "description": "Whole-window aggregates (never paginated)."
          },
          "view": {
            "description": "Versioned read-model view backing this kind (documentation parity).",
            "type": "string"
          }
        },
        "required": [
          "kind",
          "view",
          "columns",
          "rows",
          "summary"
        ],
        "type": "object"
      },
      "ReportScheduleMutationResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ReportScheduleView"
          },
          {
            "properties": {
              "mutation": {
                "$ref": "#/components/schemas/MutationMeta"
              }
            },
            "required": [
              "mutation"
            ],
            "type": "object"
          }
        ],
        "description": "Mutation envelope: applied schedule + read-your-write metadata (IF2)."
      },
      "ReportSchedulePage": {
        "description": "GET /api/report-schedules envelope.",
        "properties": {
          "next_cursor": {
            "description": "Pass back as `cursor`; absent when exhausted.",
            "type": [
              "string",
              "null"
            ]
          },
          "schedules": {
            "description": "Deterministically ordered `(name, id)`.",
            "items": {
              "$ref": "#/components/schemas/ReportScheduleView"
            },
            "type": "array"
          }
        },
        "required": [
          "schedules"
        ],
        "type": "object"
      },
      "ReportScheduleView": {
        "description": "One delivery schedule with its next-run preview (the materialized\n`next_run_at` the worker claims against) and definition coordinates.",
        "properties": {
          "cadence": {
            "$ref": "#/components/schemas/ScheduleCadence"
          },
          "created_at": {
            "type": "string"
          },
          "created_by": {
            "format": "uuid",
            "type": "string"
          },
          "day_of_month": {
            "description": "1..=28 (monthly only).",
            "format": "int32",
            "type": [
              "integer",
              "null"
            ]
          },
          "day_of_week": {
            "description": "0 = Monday .. 6 = Sunday (weekly only).",
            "format": "int32",
            "type": [
              "integer",
              "null"
            ]
          },
          "definition_kind": {
            "type": "string"
          },
          "definition_name": {
            "description": "Denormalized for the listing UI (`definition_name`, `definition_kind`).",
            "type": "string"
          },
          "enabled": {
            "type": "boolean"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "last_error": {
            "type": [
              "string",
              "null"
            ]
          },
          "last_run_at": {
            "type": [
              "string",
              "null"
            ]
          },
          "name": {
            "type": "string"
          },
          "next_run_at": {
            "description": "Next-run preview — the instant the worker will next claim.",
            "type": "string"
          },
          "recipients": {
            "description": "Recipient staff user ids.",
            "items": {
              "format": "uuid",
              "type": "string"
            },
            "type": "array"
          },
          "report_definition_id": {
            "format": "uuid",
            "type": "string"
          },
          "time_of_day": {
            "description": "Local wall-clock fire time, `HH:MM`.",
            "type": "string"
          },
          "timezone": {
            "type": "string"
          },
          "updated_at": {
            "type": "string"
          },
          "window_days": {
            "description": "Trailing-day window each run covers.",
            "format": "int32",
            "type": "integer"
          }
        },
        "required": [
          "id",
          "name",
          "report_definition_id",
          "definition_name",
          "definition_kind",
          "recipients",
          "cadence",
          "time_of_day",
          "timezone",
          "window_days",
          "enabled",
          "next_run_at",
          "created_by",
          "created_at",
          "updated_at"
        ],
        "type": "object"
      },
      "ReportSpec": {
        "description": "A stored report spec (TASKLIST R3). Every member is registry-validated;\nsee [`ReportSpec::validate`].",
        "properties": {
          "filters": {
            "items": {
              "$ref": "#/components/schemas/SpecFilter"
            },
            "type": "array"
          },
          "group_by": {
            "description": "Group-by dimensions (any projected column except `org_id`). Empty\nmeans a single grand-total row.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "measures": {
            "description": "Aggregate measures, one or more.",
            "items": {
              "$ref": "#/components/schemas/MeasureSpec"
            },
            "type": "array"
          },
          "view": {
            "$ref": "#/components/schemas/ViewId",
            "description": "The versioned read-model view this report reads (the stored `kind`\ncolumn). NEVER a physical table — the enum has no other variants."
          },
          "viz": {
            "$ref": "#/components/schemas/VizHint",
            "description": "Presentation hint (never affects the compiled SQL)."
          }
        },
        "required": [
          "view",
          "measures",
          "viz"
        ],
        "type": "object"
      },
      "RestoreDocumentRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1)."
          },
          {
            "properties": {
              "change_summary": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "version": {
                "description": "The historical version whose content the NEW version copies.",
                "format": "int32",
                "type": "integer"
              }
            },
            "required": [
              "version"
            ],
            "type": "object"
          }
        ]
      },
      "RevertDetail": {
        "description": "What the revert restored.",
        "properties": {
          "fields": {
            "description": "Record fields whose values were restored.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "reverted_seq": {
            "description": "The write-trail seq the revert stepped back over.",
            "format": "int64",
            "type": "integer"
          },
          "whole_record": {
            "description": "Whether this was a whole-record step (no explicit field list).",
            "type": "boolean"
          }
        },
        "required": [
          "reverted_seq",
          "fields",
          "whole_record"
        ],
        "type": "object"
      },
      "RevertTicketRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1): idempotency key + entity\nversion, exactly as any autosave write."
          },
          {
            "properties": {
              "fields": {
                "description": "Explicit per-field revert: restore ONLY these fields to their values\nat the target write. Omit for a whole-record step (rejected with\n`undo_reverts_only` while the record is closed).",
                "items": {
                  "type": "string"
                },
                "type": [
                  "array",
                  "null"
                ]
              },
              "seq": {
                "description": "The write-trail `seq` to step back over (from the undo stack).",
                "format": "int64",
                "type": "integer"
              }
            },
            "required": [
              "seq"
            ],
            "type": "object"
          }
        ],
        "description": "POST /api/tickets/{id}/revert body."
      },
      "RowFormat": {
        "description": "Wire format selector for an import payload.",
        "enum": [
          "json",
          "csv"
        ],
        "type": "string"
      },
      "RowOutcome": {
        "oneOf": [
          {
            "description": "Validated clean and unmapped — committing would INSERT.",
            "properties": {
              "status": {
                "enum": [
                  "ok"
                ],
                "type": "string"
              }
            },
            "required": [
              "status"
            ],
            "type": "object"
          },
          {
            "description": "Mapped, differs, update policy — committing would UPDATE.",
            "properties": {
              "status": {
                "enum": [
                  "would_update"
                ],
                "type": "string"
              }
            },
            "required": [
              "status"
            ],
            "type": "object"
          },
          {
            "description": "Nothing would happen; the reason distinguishes identical-vs-policy.",
            "properties": {
              "reason": {
                "type": "string"
              },
              "status": {
                "enum": [
                  "would_skip"
                ],
                "type": "string"
              }
            },
            "required": [
              "reason",
              "status"
            ],
            "type": "object"
          },
          {
            "description": "Validation failed or a fail-policy conflict fired; `errors` carries\nhuman-readable items for operators.",
            "properties": {
              "errors": {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "status": {
                "enum": [
                  "failed"
                ],
                "type": "string"
              }
            },
            "required": [
              "errors",
              "status"
            ],
            "type": "object"
          }
        ]
      },
      "RowReport": {
        "description": "Per-row dry-run/commit report entry. The wire shape contract from D2:\nevery row maps to exactly one of `errors[]`, `ok`, `would_skip`,\n`would_update`.",
        "properties": {
          "external_key": {
            "type": [
              "string",
              "null"
            ]
          },
          "outcome": {
            "$ref": "#/components/schemas/RowOutcome"
          },
          "row_index": {
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "row_index",
          "outcome"
        ],
        "type": "object"
      },
      "RowsPayload": {
        "description": "The encoded row source shared by dry-run and chunk posts.",
        "properties": {
          "csv": {
            "description": "Full CSV text including header row (`format=csv`). UTF-8, BOM\ntolerated; RFC 4180 quoting supported.",
            "type": [
              "string",
              "null"
            ]
          },
          "format": {
            "$ref": "#/components/schemas/RowFormat"
          },
          "json_rows": {
            "description": "Row objects as a JSON array of flat objects (`format=json`). Nulls\nbehave exactly like absent keys.",
            "type": "object"
          }
        },
        "required": [
          "format",
          "json_rows"
        ],
        "type": "object"
      },
      "RunBatchResponse": {
        "description": "POST /imports/batches/{id}/run response: the batch is queued for the\nworker exactly once; poll the batch view for counters.",
        "properties": {
          "batch_id": {
            "format": "uuid",
            "type": "string"
          },
          "job_id": {
            "format": "uuid",
            "type": "string"
          },
          "staged_chunks": {
            "format": "int32",
            "type": "integer"
          }
        },
        "required": [
          "batch_id",
          "job_id",
          "staged_chunks"
        ],
        "type": "object"
      },
      "RunReportResponse": {
        "description": "Per-row fate report — the D2 contract shape\n(`row_index → errors[] | ok | would_skip | would_update`).",
        "properties": {
          "batch_id": {
            "format": "uuid",
            "type": "string"
          },
          "conflict_policy": {
            "$ref": "#/components/schemas/ConflictPolicy"
          },
          "dry_run": {
            "type": "boolean"
          },
          "entity_kind": {
            "$ref": "#/components/schemas/EntityKind"
          },
          "rows": {
            "items": {
              "$ref": "#/components/schemas/RowReport"
            },
            "type": "array"
          },
          "summary": {
            "$ref": "#/components/schemas/ChunkSummaryWire"
          }
        },
        "required": [
          "batch_id",
          "dry_run",
          "entity_kind",
          "conflict_policy",
          "summary",
          "rows"
        ],
        "type": "object"
      },
      "ScheduleCadence": {
        "description": "Wire cadence of a schedule (snake_case slugs matching the stored\ncolumn and the worker's parser).",
        "enum": [
          "daily",
          "weekly",
          "monthly"
        ],
        "type": "string"
      },
      "ScheduleListQuery": {
        "description": "GET /api/report-schedules query.",
        "properties": {
          "cursor": {
            "description": "Opaque keyset cursor from a previous page's `next_cursor`.",
            "type": [
              "string",
              "null"
            ]
          },
          "limit": {
            "description": "Page size, clamped to [1, 200].",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "SearchQuery": {
        "properties": {
          "limit": {
            "format": "int64",
            "type": "integer"
          },
          "offset": {
            "format": "int64",
            "type": "integer"
          },
          "q": {
            "description": "Free-text query using websearch syntax: `\"exact phrases\"`,\n`-excluded`, plain terms AND-ed. Tokens ≥3 chars also match as\nsubstrings via the trigram fallback.",
            "type": "string"
          }
        },
        "required": [
          "q"
        ],
        "type": "object"
      },
      "SearchResponse": {
        "properties": {
          "kinds": {
            "description": "Kinds the principal may see, mirrored into the query filter.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "limit": {
            "format": "int64",
            "type": "integer"
          },
          "offset": {
            "format": "int64",
            "type": "integer"
          },
          "query": {
            "description": "The trimmed query actually executed.",
            "type": "string"
          },
          "results": {
            "items": {
              "$ref": "#/components/schemas/SearchResult"
            },
            "type": "array"
          },
          "total": {
            "description": "Total matches across all permitted kinds.",
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "query",
          "total",
          "kinds",
          "limit",
          "offset",
          "results"
        ],
        "type": "object"
      },
      "SearchResult": {
        "properties": {
          "entity_id": {
            "format": "uuid",
            "type": "string"
          },
          "entity_kind": {
            "description": "`ticket` | `comment` | `client` | `site` | `contact`.",
            "type": "string"
          },
          "parent_id": {
            "description": "comment → its ticket id; NULL otherwise.",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "score": {
            "description": "Blended FTS + trigram relevance score (higher is better).",
            "format": "double",
            "type": "number"
          },
          "snippet": {
            "description": "Raw body excerpt for client-side snippet rendering.",
            "type": "string"
          },
          "title": {
            "type": "string"
          }
        },
        "required": [
          "entity_kind",
          "entity_id",
          "title",
          "snippet",
          "score"
        ],
        "type": "object"
      },
      "SegmentEnd": {
        "description": "Why a timer segment ended. Preserved forever — the pause reason is\nbillable-work metadata, not a transient UI state.",
        "enum": [
          "stopped",
          "paused",
          "switched"
        ],
        "type": "string"
      },
      "SessionInfo": {
        "properties": {
          "chain_root": {
            "type": "boolean"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "current": {
            "description": "True for the session making the request.",
            "type": "boolean"
          },
          "expires_at": {
            "format": "date-time",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "user_agent": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "created_at",
          "expires_at",
          "current",
          "chain_root"
        ],
        "type": "object"
      },
      "SetChecklistItemRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1): idempotency key + entity\nversion. Absent in legacy clients — purely additive."
          },
          {
            "properties": {
              "checked": {
                "type": "boolean"
              }
            },
            "required": [
              "checked"
            ],
            "type": "object"
          }
        ]
      },
      "SetDependenciesRequest": {
        "properties": {
          "depends_on": {
            "description": "The FULL finish-to-start dependency set for the task (PUT\nsemantics): every id must be a task of the same project; the set\nmust not create a cycle (typed 422 names the offending edge).",
            "items": {
              "format": "uuid",
              "type": "string"
            },
            "type": "array"
          }
        },
        "required": [
          "depends_on"
        ],
        "type": "object"
      },
      "SetQueueRankRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams"
          },
          {
            "properties": {
              "note": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "rank": {
                "description": "Explicit queue position: 0 sorts first among overrides.",
                "format": "int32",
                "type": "integer"
              }
            },
            "required": [
              "rank"
            ],
            "type": "object"
          }
        ],
        "description": "PUT /api/dispatch/queue/{ticket_id} body."
      },
      "SetTicketFieldValueRequest": {
        "properties": {
          "value": {}
        },
        "required": [
          "value"
        ],
        "type": "object"
      },
      "SetTransitionsRequest": {
        "properties": {
          "edges": {
            "description": "The complete allowed matrix. Empty list returns the board to\nfloor-mode governance.",
            "items": {
              "$ref": "#/components/schemas/TransitionEdge"
            },
            "type": "array"
          }
        },
        "required": [
          "edges"
        ],
        "type": "object"
      },
      "SettingKind": {
        "description": "The value shapes the registry understands. A stored value must satisfy\nits declaration's kind or the write is rejected (validation is applied\nbefore persistence, never after).",
        "oneOf": [
          {
            "properties": {
              "type": {
                "enum": [
                  "boolean"
                ],
                "type": "string"
              }
            },
            "required": [
              "type"
            ],
            "type": "object"
          },
          {
            "description": "Inclusive integer range.",
            "properties": {
              "type": {
                "enum": [
                  "integer"
                ],
                "type": "string"
              },
              "value": {
                "description": "Inclusive integer range.",
                "properties": {
                  "max": {
                    "format": "int64",
                    "type": "integer"
                  },
                  "min": {
                    "format": "int64",
                    "type": "integer"
                  }
                },
                "required": [
                  "min",
                  "max"
                ],
                "type": "object"
              }
            },
            "required": [
              "value",
              "type"
            ],
            "type": "object"
          },
          {
            "description": "Free text with a hard length cap.",
            "properties": {
              "type": {
                "enum": [
                  "text"
                ],
                "type": "string"
              },
              "value": {
                "description": "Free text with a hard length cap.",
                "properties": {
                  "max_len": {
                    "minimum": 0,
                    "type": "integer"
                  }
                },
                "required": [
                  "max_len"
                ],
                "type": "object"
              }
            },
            "required": [
              "value",
              "type"
            ],
            "type": "object"
          },
          {
            "description": "Closed choice set; the wire value is the option string itself.",
            "properties": {
              "type": {
                "enum": [
                  "enumeration"
                ],
                "type": "string"
              }
            },
            "required": [
              "type"
            ],
            "type": "object"
          }
        ]
      },
      "SettingValue": {
        "description": "A concrete setting value. Only three payload types exist by design —\nricher structures are entities, not settings.",
        "oneOf": [
          {
            "type": "boolean"
          },
          {
            "format": "int64",
            "type": "integer"
          },
          {
            "type": "string"
          }
        ]
      },
      "Site": {
        "properties": {
          "address": {
            "type": [
              "string",
              "null"
            ]
          },
          "city": {
            "type": [
              "string",
              "null"
            ]
          },
          "client_id": {
            "format": "uuid",
            "type": "string"
          },
          "country": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "latitude": {
            "description": "lat/lon in decimal degrees for routing/travel estimates.",
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          },
          "longitude": {
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          },
          "name": {
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "postal_code": {
            "type": [
              "string",
              "null"
            ]
          },
          "region": {
            "type": [
              "string",
              "null"
            ]
          },
          "timezone": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "org_id",
          "client_id",
          "name",
          "created_at"
        ],
        "type": "object"
      },
      "SkillCatalogEntry": {
        "description": "GET /api/dispatch/skills envelope entry: the org skill catalog with\nholder counts (`active` = non-expired as of now).",
        "properties": {
          "active_holders": {
            "format": "int64",
            "type": "integer"
          },
          "holders": {
            "format": "int64",
            "type": "integer"
          },
          "skill": {
            "type": "string"
          }
        },
        "required": [
          "skill",
          "holders",
          "active_holders"
        ],
        "type": "object"
      },
      "SkillInput": {
        "description": "One entry of a skill replacement set.",
        "properties": {
          "expires_at": {
            "description": "Certification expiry; must be in the future when present.",
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "skill": {
            "description": "Org skill vocabulary, 1..=80 chars after trimming.",
            "type": "string"
          }
        },
        "required": [
          "skill"
        ],
        "type": "object"
      },
      "SkillListQuery": {
        "properties": {
          "slug": {
            "description": "When present, every version of this slug (newest first) instead of\nthe latest version of each slug.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "SkillView": {
        "description": "One skill on one technician.",
        "properties": {
          "expires_at": {
            "description": "Certification expiry; absent = does not expire.",
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "skill": {
            "type": "string"
          }
        },
        "required": [
          "skill"
        ],
        "type": "object"
      },
      "SkillsCatalogView": {
        "properties": {
          "skills": {
            "items": {
              "$ref": "#/components/schemas/SkillCatalogEntry"
            },
            "type": "array"
          }
        },
        "required": [
          "skills"
        ],
        "type": "object"
      },
      "SlaCalendar": {
        "description": "An org-level business-hours calendar row (`sla_calendars`). The math\ntype is [`BusinessCalendar`]; this carries its identity.",
        "properties": {
          "calendar": {
            "description": "Flattened calendar body (timezone/windows/holidays/maintenance);\n`calendar.name` mirrors `name` on write.",
            "type": "object"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "name",
          "calendar"
        ],
        "type": "object"
      },
      "SlaVerdictRequest": {
        "properties": {
          "body": {
            "type": [
              "string",
              "null"
            ]
          },
          "notify_user_ids": {
            "description": "Extra recipients from the ladder step; the assignee is added\nserver-side.",
            "items": {
              "format": "uuid",
              "type": "string"
            },
            "type": "array"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "step_id": {
            "description": "Ladder step that fired (ledger key).",
            "format": "uuid",
            "type": "string"
          },
          "target": {
            "description": "'first_response' | 'resolution'",
            "type": "string"
          },
          "ticket_id": {
            "format": "uuid",
            "type": "string"
          },
          "title": {
            "description": "Human-facing headline, e.g. \"[MER-12] SLA risk on resolution\".",
            "type": "string"
          },
          "trigger": {
            "description": "'risk' | 'breach' | 'escalate'",
            "type": "string"
          }
        },
        "required": [
          "org_id",
          "ticket_id",
          "target",
          "step_id",
          "trigger",
          "notify_user_ids",
          "title"
        ],
        "type": "object"
      },
      "SpecFilter": {
        "description": "One spec filter: catalog column + operator + typed operand.",
        "properties": {
          "column": {
            "description": "Column name from the view's FILTERABLE inventory (the narrower v1\nallowlist — filtered-but-unselected columns surprise consumers).",
            "type": "string"
          },
          "op": {
            "$ref": "#/components/schemas/FilterOp"
          },
          "value": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/FilterValue",
                "description": "Required exactly when the operator takes a value."
              }
            ]
          }
        },
        "required": [
          "column",
          "op"
        ],
        "type": "object"
      },
      "SsoExchangeRequest": {
        "properties": {
          "code": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "code"
        ],
        "type": "object"
      },
      "SsoExchangeResponse": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/TokenPair"
          },
          {
            "properties": {
              "linked": {
                "type": "boolean"
              }
            },
            "required": [
              "linked"
            ],
            "type": "object"
          }
        ]
      },
      "StageChunkRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/RowsPayload"
          },
          {
            "properties": {
              "template_id": {
                "description": "Optional saved field-mapping template applied at STAGE time, so the\nstored chunk is already in canonical columns.",
                "format": "uuid",
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "type": "object"
          }
        ],
        "description": "POST /imports/batches/{id}/stage request: uploads ONE chunk of rows to\nthe ObjectStore under a deterministic key without executing anything."
      },
      "StageChunkResponse": {
        "properties": {
          "batch_id": {
            "format": "uuid",
            "type": "string"
          },
          "chunk_index": {
            "description": "Index of the chunk just staged (its deterministic key suffix).",
            "format": "int32",
            "type": "integer"
          },
          "staged_chunks": {
            "description": "Total staged chunks after this upload — the worker's runbook length.",
            "format": "int32",
            "type": "integer"
          }
        },
        "required": [
          "batch_id",
          "chunk_index",
          "staged_chunks"
        ],
        "type": "object"
      },
      "StartTimerRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1): idempotency key. Absent in\nlegacy clients — purely additive. (Creates carry no version.)"
          },
          {
            "properties": {
              "ticket_id": {
                "format": "uuid",
                "type": "string"
              }
            },
            "required": [
              "ticket_id"
            ],
            "type": "object"
          }
        ]
      },
      "StopTimerRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1): idempotency key + entity\nversion. Absent in legacy clients — purely additive. A retried stop\nreplays the original time entry instead of failing \"no active timer\"."
          },
          {
            "properties": {
              "billable": {
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "notes": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "reason": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "session_id": {
                "description": "Omit to stop the caller's active timer.",
                "format": "uuid",
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "type": "object"
          }
        ]
      },
      "SubmitTravelDraftRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams"
          }
        ],
        "description": "POST /api/dispatch/travel-drafts/{id}/submit body."
      },
      "TaskListQuery": {
        "properties": {
          "assignee_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "limit": {
            "format": "int64",
            "type": "integer"
          },
          "milestone": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "offset": {
            "format": "int64",
            "type": "integer"
          },
          "phase_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/TaskStatus"
              }
            ]
          }
        },
        "type": "object"
      },
      "TaskMutationResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ProjectTask"
          },
          {
            "properties": {
              "mutation": {
                "$ref": "#/components/schemas/MutationMeta"
              }
            },
            "required": [
              "mutation"
            ],
            "type": "object"
          }
        ]
      },
      "TaskStatus": {
        "description": "Lifecycle of a task. `completed` is reached ONLY through the dedicated\ncomplete endpoint, which enforces dependency readiness and emits the\ncompletion (+ milestone billing seam) events.",
        "enum": [
          "pending",
          "in_progress",
          "blocked",
          "completed",
          "cancelled"
        ],
        "type": "string"
      },
      "TeamRangeQuery": {
        "properties": {
          "from": {
            "description": "Inclusive window start (default: today's UTC midnight minus 1 day).",
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "to": {
            "description": "Exclusive window end (default: `from` + 8 days).",
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "TechnicianCapacity": {
        "description": "One technician across the whole horizon.",
        "properties": {
          "days": {
            "items": {
              "$ref": "#/components/schemas/DayCapacity"
            },
            "type": "array"
          },
          "display_name": {
            "type": "string"
          },
          "user_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "user_id",
          "display_name",
          "days"
        ],
        "type": "object"
      },
      "TechnicianView": {
        "description": "One technician column: capacity stats plus everything the board draws\nin the column (bookings, on-call, exclusions, availability windows).",
        "properties": {
          "appointments": {
            "items": {
              "$ref": "#/components/schemas/DispatchAppointment"
            },
            "type": "array"
          },
          "availability_windows": {
            "items": {
              "$ref": "#/components/schemas/AvailabilityWindow"
            },
            "type": "array"
          },
          "available_minutes": {
            "description": "Working minutes covered by availability windows minus exclusions\nover the day window (`core_domain::scheduling::covered_minutes`).",
            "format": "int64",
            "type": "integer"
          },
          "booked_minutes": {
            "description": "Union of live booking minutes clipped to the day window.",
            "format": "int64",
            "type": "integer"
          },
          "display_name": {
            "type": "string"
          },
          "exclusions": {
            "items": {
              "$ref": "#/components/schemas/CalendarExclusion"
            },
            "type": "array"
          },
          "on_call": {
            "items": {
              "$ref": "#/components/schemas/OnCallBlock"
            },
            "type": "array"
          },
          "timezone": {
            "type": "string"
          },
          "user_id": {
            "format": "uuid",
            "type": "string"
          },
          "utilization_percent": {
            "description": "0–100+, where >100 is over-capacity (the Ember warning state).",
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "user_id",
          "display_name",
          "timezone",
          "available_minutes",
          "booked_minutes",
          "utilization_percent",
          "appointments",
          "on_call",
          "exclusions",
          "availability_windows"
        ],
        "type": "object"
      },
      "TemplateListQuery": {
        "properties": {
          "source_system": {
            "description": "Narrow the listing to one source system.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "TemplateMutationResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ProjectTemplate"
          }
        ]
      },
      "TemplateViewResponse": {
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "created_by": {
            "format": "uuid",
            "type": "string"
          },
          "created_by_kind": {
            "type": "string"
          },
          "entity_kind": {
            "$ref": "#/components/schemas/EntityKind"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "mapping": {
            "type": "object"
          },
          "name": {
            "type": "string"
          },
          "source_system": {
            "type": "string"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "id",
          "name",
          "source_system",
          "entity_kind",
          "mapping",
          "created_by",
          "created_by_kind",
          "created_at",
          "updated_at"
        ],
        "type": "object"
      },
      "TestConnectionRequest": {
        "description": "Request to test the connection to an AI provider.",
        "properties": {
          "provider": {
            "description": "Provider to test. If omitted, tests the currently active provider in settings.",
            "type": [
              "string",
              "null"
            ]
          },
          "test_prompt": {
            "description": "Optional prompt to test with.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "TestConnectionResponse": {
        "description": "Result of testing an AI provider connection.",
        "properties": {
          "latency_ms": {
            "format": "int64",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          },
          "message": {
            "description": "Descriptive status message or reason on failure.",
            "type": "string"
          },
          "ok": {
            "type": "boolean"
          },
          "provider": {
            "type": "string"
          }
        },
        "required": [
          "provider",
          "ok",
          "message"
        ],
        "type": "object"
      },
      "TestFireResponse": {
        "properties": {
          "event_id": {
            "description": "The envelope id to look for in the delivery log.",
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "event_id"
        ],
        "type": "object"
      },
      "Ticket": {
        "properties": {
          "assignee_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "board_id": {
            "format": "uuid",
            "type": "string"
          },
          "body": {
            "type": [
              "string",
              "null"
            ]
          },
          "category": {
            "$ref": "#/components/schemas/TicketStatusCategory",
            "description": "Denormalized from the board status for cheap filtering/sorting."
          },
          "client_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "contact_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "due_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "number": {
            "$ref": "#/components/schemas/TicketNumber"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "priority": {
            "$ref": "#/components/schemas/Priority"
          },
          "requester_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "resolved_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "site_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "status_id": {
            "format": "uuid",
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "number",
          "board_id",
          "status_id",
          "title",
          "priority",
          "category",
          "created_at",
          "updated_at"
        ],
        "type": "object"
      },
      "TicketChecklistMutationResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/TicketChecklistView"
          },
          {
            "properties": {
              "mutation": {
                "$ref": "#/components/schemas/MutationMeta"
              }
            },
            "required": [
              "mutation"
            ],
            "type": "object"
          }
        ],
        "description": "Same additive envelope for checklist writes: the full checklist view at\nthe top level (unchanged shape) plus the read-your-write metadata for\nthe affected item."
      },
      "TicketChecklistView": {
        "description": "GET response for a ticket's checklist: instances, derived progress,\nand the board's live enforcement posture. `blocking` lists the unchecked\nREQUIRED items when enforcement is active (empty otherwise).",
        "properties": {
          "blocking": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "enforcement_active": {
            "type": "boolean"
          },
          "items": {
            "items": {
              "$ref": "#/components/schemas/ChecklistItem"
            },
            "type": "array"
          },
          "progress": {
            "$ref": "#/components/schemas/ChecklistProgress"
          }
        },
        "required": [
          "items",
          "progress",
          "enforcement_active",
          "blocking"
        ],
        "type": "object"
      },
      "TicketComment": {
        "description": "A structured ticket note. Taxonomy: internal / client-visible /\nin-house update. `kind` gates portal visibility and email fan-out.",
        "properties": {
          "author_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "body": {
            "type": "string"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "kind": {
            "$ref": "#/components/schemas/NoteKind"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "ticket_id": {
            "format": "uuid",
            "type": "string"
          },
          "updated_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "org_id",
          "ticket_id",
          "kind",
          "body",
          "created_at"
        ],
        "type": "object"
      },
      "TicketCommentMutationResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/TicketComment"
          },
          {
            "properties": {
              "mutation": {
                "$ref": "#/components/schemas/MutationMeta"
              }
            },
            "required": [
              "mutation"
            ],
            "type": "object"
          }
        ],
        "description": "Same additive envelope for comments (plain comment body)."
      },
      "TicketCustomFieldValue": {
        "description": "One stored ticket value with its definition context.",
        "properties": {
          "field_id": {
            "format": "uuid",
            "type": "string"
          },
          "kind": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "required": {
            "type": "boolean"
          },
          "sort_order": {
            "format": "int32",
            "type": "integer"
          },
          "value": {}
        },
        "required": [
          "field_id",
          "name",
          "kind",
          "required",
          "sort_order",
          "value"
        ],
        "type": "object"
      },
      "TicketFieldInput": {
        "description": "One value assignment on a ticket create/patch: raw JSON validated against\nits definition server-side.",
        "properties": {
          "field_id": {
            "format": "uuid",
            "type": "string"
          },
          "value": {}
        },
        "required": [
          "field_id",
          "value"
        ],
        "type": "object"
      },
      "TicketListQuery": {
        "properties": {
          "assignee_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "board_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "category": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/TicketStatusCategory"
              }
            ]
          },
          "client_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "limit": {
            "format": "int64",
            "type": "integer"
          },
          "offset": {
            "format": "int64",
            "type": "integer"
          },
          "priority": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/Priority"
              }
            ]
          }
        },
        "type": "object"
      },
      "TicketMatch": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MyWorkItem"
          },
          {
            "properties": {
              "candidates": {
                "description": "Active technicians sorted best-first (fewest missing, then name).",
                "items": {
                  "$ref": "#/components/schemas/MatchCandidate"
                },
                "type": "array"
              },
              "required_skills": {
                "items": {
                  "type": "string"
                },
                "type": "array"
              }
            },
            "required": [
              "required_skills",
              "candidates"
            ],
            "type": "object"
          }
        ],
        "description": "Skills-matched staffing for one unassigned ticket. Tickets with no\nrequired skills are not listed (the plain queue ordering covers them)."
      },
      "TicketMutationResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/TicketWithFields"
          },
          {
            "properties": {
              "mutation": {
                "$ref": "#/components/schemas/MutationMeta"
              }
            },
            "required": [
              "mutation"
            ],
            "type": "object"
          }
        ],
        "description": "Instant-first mutation response (IF2): the enriched ticket fields at the\ntop level (unchanged shape) plus the additive `mutation` metadata — the\napplied snapshot, monotonic per-entity `seq`/`version`, and the prior\nand new values that make undo a core capability."
      },
      "TicketNumber": {
        "description": "Human-facing ticket number, e.g. `MER-2841`. Globally unique per org,\nassigned from a per-org sequence.",
        "type": "string"
      },
      "TicketRevertResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/TicketWithFields"
          },
          {
            "properties": {
              "mutation": {
                "$ref": "#/components/schemas/MutationMeta"
              },
              "revert": {
                "$ref": "#/components/schemas/RevertDetail"
              }
            },
            "required": [
              "mutation",
              "revert"
            ],
            "type": "object"
          }
        ],
        "description": "The reverted ticket with the mutation envelope, plus what was reverted.\nDeserializable so an IF1 idempotent replay can reconstruct the exact\nstored response."
      },
      "TicketSkillsMutationResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/TicketSkillsView"
          },
          {
            "properties": {
              "mutation": {
                "$ref": "#/components/schemas/MutationMeta"
              }
            },
            "required": [
              "mutation"
            ],
            "type": "object"
          }
        ],
        "description": "The full-replace mutation envelope (IF2)."
      },
      "TicketSkillsView": {
        "properties": {
          "skills": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "ticket_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "ticket_id",
          "skills"
        ],
        "type": "object"
      },
      "TicketSlaState": {
        "description": "Per-ticket SLA clock state. Accumulates paused business seconds so a\nWaiting stretch does not consume the resolution budget.",
        "properties": {
          "breached": {
            "type": "boolean"
          },
          "first_responded_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "first_response_due": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "paused_business_secs": {
            "description": "Business seconds accumulated while the clock was paused.",
            "format": "int64",
            "type": "integer"
          },
          "paused_since": {
            "description": "When the current pause began (None while running).",
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "policy_id": {
            "format": "uuid",
            "type": "string"
          },
          "resolution_due": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "ticket_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "org_id",
          "ticket_id",
          "policy_id",
          "paused_business_secs",
          "breached"
        ],
        "type": "object"
      },
      "TicketSlaStatus": {
        "description": "Live SLA clock readout for one ticket (badge + countdown surfaces).",
        "properties": {
          "breached": {
            "type": "boolean"
          },
          "minutes_remaining": {
            "description": "Business minutes left on the resolution budget (negative = over).",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          },
          "paused": {
            "description": "True while a Waiting-category pause is open.",
            "type": "boolean"
          },
          "state": {
            "$ref": "#/components/schemas/TicketSlaState"
          }
        },
        "required": [
          "state",
          "paused",
          "breached"
        ],
        "type": "object"
      },
      "TicketStatusCategory": {
        "description": "The four semantic categories every ticket status maps to (§5).\nCustomization (labels, ordering, per-board sets) can never add, remove, or\nre-bind these: SLA timers, pause logic, automations, billing, and reports\nbind to the category, not the label.",
        "enum": [
          "open",
          "in_progress",
          "waiting",
          "closed"
        ],
        "type": "string"
      },
      "TicketStatusMutationResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Ticket"
          },
          {
            "properties": {
              "mutation": {
                "$ref": "#/components/schemas/MutationMeta"
              }
            },
            "required": [
              "mutation"
            ],
            "type": "object"
          }
        ],
        "description": "Same additive envelope for status transitions (plain ticket body)."
      },
      "TicketWithFields": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Ticket"
          },
          {
            "properties": {
              "custom_fields": {
                "items": {
                  "$ref": "#/components/schemas/TicketCustomFieldValue"
                },
                "type": "array"
              }
            },
            "required": [
              "custom_fields"
            ],
            "type": "object"
          }
        ],
        "description": "A ticket payload enriched with its custom-field values (detail + list)."
      },
      "TimeEntry": {
        "description": "A durable, reviewable record of worked time. Created from a timer session\nor entered manually; subject to bulk review and approval workflows.",
        "properties": {
          "billable": {
            "type": "boolean"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "ended_at": {
            "format": "date-time",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "minutes": {
            "description": "Worked seconds — authoritative, derived on write, never recomputed.",
            "format": "int64",
            "type": "integer"
          },
          "notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "started_at": {
            "format": "date-time",
            "type": "string"
          },
          "ticket_id": {
            "format": "uuid",
            "type": "string"
          },
          "timer_session_id": {
            "description": "Origin: timer-derived entries keep their session for audit.",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "user_id": {
            "format": "uuid",
            "type": "string"
          },
          "work_type": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "org_id",
          "ticket_id",
          "user_id",
          "started_at",
          "ended_at",
          "minutes",
          "billable",
          "created_at"
        ],
        "type": "object"
      },
      "TimeEntryMutationResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/TimeEntry"
          },
          {
            "properties": {
              "mutation": {
                "$ref": "#/components/schemas/MutationMeta"
              }
            },
            "required": [
              "mutation"
            ],
            "type": "object"
          }
        ],
        "description": "Same additive envelope for the stop flow (time-entry body)."
      },
      "TimeSettingsResponse": {
        "properties": {
          "eod_nudge_hour": {
            "description": "Local hour (member timezones) the EOD audit fires at.",
            "format": "int32",
            "type": "integer"
          },
          "eod_nudges_enabled": {
            "type": "boolean"
          },
          "time_gap_min_minutes": {
            "description": "Active days logging under this many minutes are gap days.",
            "format": "int32",
            "type": "integer"
          }
        },
        "required": [
          "eod_nudges_enabled",
          "eod_nudge_hour",
          "time_gap_min_minutes"
        ],
        "type": "object"
      },
      "TimerMutationResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/TimerSession"
          },
          {
            "properties": {
              "mutation": {
                "$ref": "#/components/schemas/MutationMeta"
              }
            },
            "required": [
              "mutation"
            ],
            "type": "object"
          }
        ],
        "description": "Instant-first mutation response (IF2): session fields at the top level\n(unchanged shape) plus the additive `mutation` metadata."
      },
      "TimerSegment": {
        "description": "A contiguous running interval within a timer session.",
        "properties": {
          "end_kind": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/SegmentEnd"
              }
            ]
          },
          "ended_at": {
            "description": "None while this segment is running.",
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "reason": {
            "description": "Free-text reason recorded at pause time (\"on call with vendor\").",
            "type": [
              "string",
              "null"
            ]
          },
          "started_at": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "started_at"
        ],
        "type": "object"
      },
      "TimerSession": {
        "description": "One user's timer against one ticket. At most one session per user is\never running — enforced by [`TimerSession::start_switch`].",
        "properties": {
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "org_id": {
            "format": "uuid",
            "type": "string"
          },
          "segments": {
            "items": {
              "$ref": "#/components/schemas/TimerSegment"
            },
            "type": "array"
          },
          "started_at": {
            "format": "date-time",
            "type": "string"
          },
          "stopped_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "ticket_id": {
            "format": "uuid",
            "type": "string"
          },
          "user_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "id",
          "org_id",
          "user_id",
          "ticket_id",
          "started_at",
          "segments"
        ],
        "type": "object"
      },
      "TokenPair": {
        "description": "Token pair returned by all auth flows.",
        "properties": {
          "access_token": {
            "type": "string"
          },
          "expires_in": {
            "description": "Access token TTL in seconds.",
            "format": "int64",
            "type": "integer"
          },
          "refresh_token": {
            "type": "string"
          },
          "session_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "access_token",
          "refresh_token",
          "session_id",
          "expires_in"
        ],
        "type": "object"
      },
      "TotpDisableRequest": {
        "properties": {
          "code": {
            "description": "Current TOTP code or a recovery code.",
            "type": "string"
          },
          "password": {
            "type": "string"
          }
        },
        "required": [
          "password",
          "code"
        ],
        "type": "object"
      },
      "TotpEnrollBeginResponse": {
        "properties": {
          "otpauth_url": {
            "description": "Standard otpauth:// URI (renderable as QR by clients).",
            "type": "string"
          },
          "secret_base32": {
            "description": "Base32 secret for manual authenticator entry. Shown exactly once.",
            "type": "string"
          }
        },
        "required": [
          "secret_base32",
          "otpauth_url"
        ],
        "type": "object"
      },
      "TotpEnrollVerifyRequest": {
        "properties": {
          "code": {
            "type": "string"
          }
        },
        "required": [
          "code"
        ],
        "type": "object"
      },
      "TransitionEdge": {
        "description": "One directed edge in a board's explicit transition matrix. Both ids must\nbelong to statuses of the SAME board (enforced here, and by composite FKs\nin storage).",
        "properties": {
          "from_status_id": {
            "format": "uuid",
            "type": "string"
          },
          "to_status_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "from_status_id",
          "to_status_id"
        ],
        "type": "object"
      },
      "TravelDraftMutationResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/TravelDraftView"
          },
          {
            "properties": {
              "mutation": {
                "$ref": "#/components/schemas/MutationMeta"
              }
            },
            "required": [
              "mutation"
            ],
            "type": "object"
          }
        ],
        "description": "Mutation envelope: draft fields at the top level plus the additive\n`mutation` metadata (IF2)."
      },
      "TravelDraftView": {
        "description": "One travel/mileage draft.",
        "properties": {
          "billable": {
            "type": "boolean"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "distance": {
            "format": "double",
            "type": "number"
          },
          "distance_unit": {
            "description": "`km` | `mi`.",
            "type": "string"
          },
          "ended_at": {
            "format": "date-time",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "notes": {
            "type": [
              "string",
              "null"
            ]
          },
          "started_at": {
            "format": "date-time",
            "type": "string"
          },
          "status": {
            "description": "`draft` | `submitted`.",
            "type": "string"
          },
          "submitted_time_entry_id": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "ticket_id": {
            "format": "uuid",
            "type": "string"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          },
          "user_id": {
            "format": "uuid",
            "type": "string"
          },
          "vehicle": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "user_id",
          "ticket_id",
          "started_at",
          "ended_at",
          "distance",
          "distance_unit",
          "vehicle",
          "billable",
          "status",
          "created_at",
          "updated_at"
        ],
        "type": "object"
      },
      "UndoFieldStep": {
        "description": "One field of one applied write — per-field undo granularity.",
        "properties": {
          "actor_id": {
            "format": "uuid",
            "type": "string"
          },
          "actor_kind": {
            "type": "string"
          },
          "changed": {
            "type": "boolean"
          },
          "created_at": {
            "type": "string"
          },
          "field": {
            "type": "string"
          },
          "new_value": {
            "description": "Value after the write (absent keys read as `null`).",
            "type": [
              "object",
              "null"
            ]
          },
          "op": {
            "type": "string"
          },
          "prior": {
            "description": "Value before the write (absent keys read as `null`).",
            "type": [
              "object",
              "null"
            ]
          },
          "seq": {
            "format": "int64",
            "type": "integer"
          },
          "write_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "write_id",
          "seq",
          "op",
          "field",
          "prior",
          "new_value",
          "changed",
          "actor_id",
          "actor_kind",
          "created_at"
        ],
        "type": "object"
      },
      "UndoMode": {
        "description": "The record's undo posture: `open` = near-total undo; `reverts_only` =\nexplicit actioned per-field reverts only (record is closed).",
        "enum": [
          "open",
          "reverts_only"
        ],
        "type": "string"
      },
      "UndoStackQuery": {
        "properties": {
          "limit": {
            "description": "Maximum steps / field rows returned (1–200, default 50). Newest\nfirst; the first step's `seq` is the record's current version.",
            "format": "int64",
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "UndoStackResponse": {
        "properties": {
          "current_version": {
            "description": "The record's current version — echo it as `version` on a revert.",
            "format": "int64",
            "type": "integer"
          },
          "entity": {
            "type": "string"
          },
          "entity_id": {
            "format": "uuid",
            "type": "string"
          },
          "fields": {
            "description": "Per-field history, newest write first.",
            "items": {
              "$ref": "#/components/schemas/UndoFieldStep"
            },
            "type": "array"
          },
          "mode": {
            "$ref": "#/components/schemas/UndoMode",
            "description": "Near-total (`open`) vs actioned-reverts-only (`reverts_only`)."
          },
          "steps": {
            "description": "Applied writes, newest first.",
            "items": {
              "$ref": "#/components/schemas/UndoStep"
            },
            "type": "array"
          }
        },
        "required": [
          "entity",
          "entity_id",
          "mode",
          "current_version",
          "steps",
          "fields"
        ],
        "type": "object"
      },
      "UndoStep": {
        "description": "One applied write on the record — one step of the undo stack.",
        "properties": {
          "actor_id": {
            "format": "uuid",
            "type": "string"
          },
          "actor_kind": {
            "description": "`human` | `agent` | ... (the audit actor vocabulary).",
            "type": "string"
          },
          "after": {
            "description": "Applied entity snapshot.",
            "type": "object"
          },
          "before": {
            "description": "Prior entity snapshot; `null` on creates.",
            "type": [
              "object",
              "null"
            ]
          },
          "created_at": {
            "type": "string"
          },
          "idempotency_key": {
            "type": [
              "string",
              "null"
            ]
          },
          "op": {
            "description": "Machine op name (`create`, `update`, `status_change`, `revert`, ...).",
            "type": "string"
          },
          "restorable": {
            "description": "The revert path can restore this write's prior values (`create`\nsteps are visible history but not value-restorable).",
            "type": "boolean"
          },
          "seq": {
            "description": "Per-entity monotonic write number (the version this write produced).",
            "format": "int64",
            "type": "integer"
          },
          "write_id": {
            "description": "Trail row id (stable reference for actioned reverts).",
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "write_id",
          "seq",
          "op",
          "actor_id",
          "actor_kind",
          "before",
          "after",
          "restorable",
          "created_at"
        ],
        "type": "object"
      },
      "UnreadCount": {
        "properties": {
          "count": {
            "format": "int64",
            "type": "integer"
          }
        },
        "required": [
          "count"
        ],
        "type": "object"
      },
      "UpdateArticleRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1)."
          },
          {
            "properties": {
              "body": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "category_id": {
                "description": "`null` clears the category; omit to leave it untouched.",
                "format": "uuid",
                "type": [
                  "string",
                  "null"
                ]
              },
              "client_visible": {
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "status": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/KbArticleStatus"
                  }
                ]
              },
              "title": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "type": "object"
          }
        ]
      },
      "UpdateCalendarRequest": {
        "properties": {
          "holidays": {},
          "maintenance": {},
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "timezone": {
            "type": [
              "string",
              "null"
            ]
          },
          "windows": {}
        },
        "type": "object"
      },
      "UpdateCategoryRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1)."
          },
          {
            "properties": {
              "client_visible": {
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "description": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "name": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "position": {
                "format": "int32",
                "type": [
                  "integer",
                  "null"
                ]
              }
            },
            "type": "object"
          }
        ]
      },
      "UpdateDocumentRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1)."
          },
          {
            "properties": {
              "body": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "change_summary": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "title": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "type": "object"
          }
        ]
      },
      "UpdateFieldDefRequest": {
        "properties": {
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "options": {
            "description": "Replaces the option set for choice kinds.",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "required": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "sort_order": {
            "format": "int32",
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "UpdateGroupRequest": {
        "properties": {
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "position": {
            "format": "int32",
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "UpdatePreferenceRequest": {
        "properties": {
          "email": {
            "type": "boolean"
          },
          "in_app": {
            "type": "boolean"
          },
          "kind": {
            "$ref": "#/components/schemas/NotificationKind"
          },
          "quiet_from": {
            "description": "`HH:MM` pair; both bounds together or neither.",
            "type": [
              "string",
              "null"
            ]
          },
          "quiet_until": {
            "type": [
              "string",
              "null"
            ]
          },
          "timezone": {
            "description": "IANA timezone for the window; defaults to UTC.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "kind",
          "in_app",
          "email"
        ],
        "type": "object"
      },
      "UpdateReportDefinitionRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams"
          },
          {
            "properties": {
              "description": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "name": {
                "type": "string"
              },
              "scope": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/DefinitionScope",
                    "description": "New visibility; `org` requires admin and non-admins keep `self`."
                  }
                ]
              },
              "spec": {
                "$ref": "#/components/schemas/ReportSpec"
              }
            },
            "required": [
              "name",
              "spec"
            ],
            "type": "object"
          }
        ],
        "description": "PUT /api/report-definitions/{id} body — full-replace semantics: every\nmember is applied; `description: null` clears it."
      },
      "UpdateReportScheduleRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams"
          },
          {
            "properties": {
              "cadence": {
                "$ref": "#/components/schemas/ScheduleCadence"
              },
              "day_of_month": {
                "format": "int32",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "day_of_week": {
                "format": "int32",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "enabled": {
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "name": {
                "type": "string"
              },
              "recipients": {
                "items": {
                  "format": "uuid",
                  "type": "string"
                },
                "type": "array"
              },
              "report_definition_id": {
                "format": "uuid",
                "type": "string"
              },
              "time_of_day": {
                "type": "string"
              },
              "timezone": {
                "type": "string"
              },
              "window_days": {
                "format": "int32",
                "type": [
                  "integer",
                  "null"
                ]
              }
            },
            "required": [
              "name",
              "report_definition_id",
              "recipients",
              "cadence",
              "time_of_day",
              "timezone"
            ],
            "type": "object"
          }
        ],
        "description": "PUT /api/report-schedules/{id} body — full-replace semantics; every\nmember is applied and the next-run preview recomputes."
      },
      "UpdateRuleRequest": {
        "properties": {
          "actions": {},
          "board_id": {
            "description": "`Some(Some(id))` scopes; `Some(None)` clears to all boards.",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "conditions": {},
          "enabled": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "trigger_event": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "UpdateSettingRequest": {
        "properties": {
          "key": {
            "type": "string"
          },
          "value": {
            "description": "Must satisfy the declaration's kind or the request is rejected 422."
          }
        },
        "required": [
          "key",
          "value"
        ],
        "type": "object"
      },
      "UpdateStatusRequest": {
        "properties": {
          "category": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/TicketStatusCategory",
                "description": "Re-binds the semantic category; behavior follows immediately (§5)."
              }
            ]
          },
          "is_entry": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "sort_order": {
            "format": "int32",
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "UpdateTemplateRequest": {
        "description": "PUT /api/imports/templates/{id} request — all fields optional.",
        "properties": {
          "entity_kind": {
            "$ref": "#/components/schemas/EntityKind"
          },
          "mapping": {
            "type": "object"
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "source_system": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "entity_kind",
          "mapping"
        ],
        "type": "object"
      },
      "UpdateTimeSettingsRequest": {
        "properties": {
          "eod_nudge_hour": {
            "format": "int32",
            "type": "integer"
          },
          "eod_nudges_enabled": {
            "type": "boolean"
          },
          "time_gap_min_minutes": {
            "format": "int32",
            "type": "integer"
          }
        },
        "required": [
          "eod_nudges_enabled",
          "eod_nudge_hour",
          "time_gap_min_minutes"
        ],
        "type": "object"
      },
      "UpdateWebhookRequest": {
        "properties": {
          "enabled": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "event_types": {
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "url": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "UpsertMemberRequest": {
        "properties": {
          "role": {
            "$ref": "#/components/schemas/BoardRole"
          },
          "user_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "user_id",
          "role"
        ],
        "type": "object"
      },
      "UpsertProviderRequest": {
        "properties": {
          "client_id": {
            "type": "string"
          },
          "client_secret": {
            "description": "Write-only: stored encrypted at rest, never returned.",
            "type": "string"
          },
          "discovery_url": {
            "description": "Typically `{issuer}/.well-known/openid-configuration`.",
            "type": "string"
          },
          "display_name": {
            "type": "string"
          },
          "enabled": {
            "type": "boolean"
          },
          "issuer": {
            "type": "string"
          },
          "jit_provisioning": {
            "type": "boolean"
          }
        },
        "required": [
          "display_name",
          "issuer",
          "discovery_url",
          "client_id",
          "client_secret"
        ],
        "type": "object"
      },
      "UserSkillsMutationResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/UserSkillsView"
          },
          {
            "properties": {
              "mutation": {
                "$ref": "#/components/schemas/MutationMeta"
              }
            },
            "required": [
              "mutation"
            ],
            "type": "object"
          }
        ],
        "description": "The full-replace mutation envelope (IF2)."
      },
      "UserSkillsView": {
        "properties": {
          "skills": {
            "items": {
              "$ref": "#/components/schemas/SkillView"
            },
            "type": "array"
          },
          "user_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "user_id",
          "skills"
        ],
        "type": "object"
      },
      "ValueView": {
        "description": "One effective value: registry default overlaid by any stored override.",
        "properties": {
          "key": {
            "type": "string"
          },
          "value": {
            "description": "JSON payload typed by the declaration's kind."
          }
        },
        "required": [
          "key",
          "value"
        ],
        "type": "object"
      },
      "VerdictResponse": {
        "properties": {
          "applied": {
            "description": "False when the ledger had already recorded this fire (idempotent\nreplay after a worker retry) — nothing was written or notified.",
            "type": "boolean"
          },
          "reason": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "applied"
        ],
        "type": "object"
      },
      "ViewId": {
        "description": "Versioned read-model views. Variant ↔ physical view name is frozen\nalongside the schema-version suffix; adding a view is additive.\n\nThe serde encoding is the view SLUG (`snake_case`) — the same string the\nstored-spec `kind` column carries (R3 registry backing) — so a definition\nround-trips through JSON without a parallel name table.",
        "enum": [
          "tickets",
          "time_entries",
          "sla_outcomes",
          "gap_days",
          "first_response"
        ],
        "type": "string"
      },
      "ViewListQuery": {
        "properties": {
          "project_id": {
            "description": "Scope to one project's views; omit for the org's ENTIRE view set.",
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      },
      "ViewMutationResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/ProjectView"
          }
        ]
      },
      "VizHint": {
        "description": "Visualization hint the report builder renders with (ADR 0001: Recharts\nbar/line/pie/table on the frontend). Pure presentation metadata — it\nnever influences the compiled SQL.",
        "enum": [
          "bar",
          "line",
          "pie",
          "table"
        ],
        "type": "string"
      },
      "VoidInvoiceRequest": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MutationParams",
            "description": "Instant-first autosave parameters (IF1): idempotency key +\nIf-Match `version`."
          }
        ]
      },
      "WebauthnBeginResponse": {
        "properties": {
          "challenge_token": {
            "description": "Opaque ceremony binding — pass back to finish.",
            "type": "string"
          },
          "public_key": {
            "description": "CreationOptions for navigator.credentials.create()/get().",
            "type": "object"
          }
        },
        "required": [
          "public_key",
          "challenge_token"
        ],
        "type": "object"
      },
      "WebauthnCredentialInfo": {
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "last_used_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "label",
          "created_at"
        ],
        "type": "object"
      },
      "WebauthnLoginFinishRequest": {
        "properties": {
          "challenge_token": {
            "type": "string"
          },
          "credential": {
            "description": "The PublicKeyCredential from navigator.credentials.get().",
            "type": "object"
          }
        },
        "required": [
          "challenge_token",
          "credential"
        ],
        "type": "object"
      },
      "WebauthnRegisterFinishRequest": {
        "properties": {
          "challenge_token": {
            "type": "string"
          },
          "credential": {
            "description": "The PublicKeyCredential from navigator.credentials.create().",
            "type": "object"
          },
          "label": {
            "description": "Label shown on the security settings page.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "challenge_token",
          "credential"
        ],
        "type": "object"
      },
      "WebauthnRemoveRequest": {
        "properties": {
          "password": {
            "type": "string"
          }
        },
        "required": [
          "password"
        ],
        "type": "object"
      },
      "WebhookList": {
        "properties": {
          "webhooks": {
            "items": {
              "$ref": "#/components/schemas/WebhookView"
            },
            "type": "array"
          }
        },
        "required": [
          "webhooks"
        ],
        "type": "object"
      },
      "WebhookSecretResponse": {
        "description": "Returned by create ONLY — carries the signing secret in plaintext one\nfinal time. There is deliberately no read-back path.",
        "properties": {
          "secret": {
            "type": "string"
          },
          "webhook": {
            "$ref": "#/components/schemas/WebhookView"
          }
        },
        "required": [
          "webhook",
          "secret"
        ],
        "type": "object"
      },
      "WebhookView": {
        "properties": {
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "created_by": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "enabled": {
            "type": "boolean"
          },
          "event_types": {
            "description": "Empty array = wildcard (all event types).",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "url": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "url",
          "event_types",
          "enabled",
          "created_at"
        ],
        "type": "object"
      }
    }
  },
  "info": {
    "description": "The single write surface for Project Meridian. All mutations flow through this API and emit domain events.",
    "license": {
      "identifier": "AGPL-3.0-or-later",
      "name": "AGPL-3.0-or-later"
    },
    "title": "Meridian Core API",
    "version": "0.1.0"
  },
  "openapi": "3.1.0",
  "paths": {
    "/api/v1/agent-proposals": {
      "get": {
        "operationId": "agent_proposals_list",
        "parameters": [
          {
            "description": "Filter by lifecycle state.",
            "in": "query",
            "name": "status",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Opaque keyset cursor from a previous page's `next_cursor`.",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Page size, clamped to [1, 200].",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "format": "int64",
              "type": [
                "integer",
                "null"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentProposalPage"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/agent-proposals — cursor-paged listing, newest first.",
        "tags": [
          "agent-platform"
        ]
      },
      "post": {
        "operationId": "agent_proposals_create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateProposalRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateProposalResponse"
                }
              }
            },
            "description": ""
          },
          "403": {
            "description": "capability not granted (deny-by-default)"
          },
          "422": {
            "description": "validation failed"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/agent-proposals — file a proposal (IF8). Accepts human-JWT\ncallers for administrative simulation, but the API-key/machine path is\nthe intended caller: the machine principal's key id becomes the\nagent_ref when none is supplied. The dial position is captured from\nthe capability's grant row at creation time.",
        "tags": [
          "agent-platform"
        ]
      }
    },
    "/api/v1/agent-proposals/{id}": {
      "get": {
        "operationId": "agent_proposals_get",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentProposalView"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/agent-proposals/{id}.",
        "tags": [
          "agent-platform"
        ]
      }
    },
    "/api/v1/agent-proposals/{id}/approve": {
      "post": {
        "operationId": "agent_proposals_approve",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DecideProposalRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentProposalView"
                }
              }
            },
            "description": ""
          },
          "403": {
            "description": "not a permitted approver"
          },
          "404": {
            "description": "not in scope"
          },
          "409": {
            "description": "proposal already decided"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/agent-proposals/{id}/approve — decide FOR. Approved ticket\nupdate proposals apply immediately through the IF1 instant-first path\nin the SAME transaction (idempotency-keyed, version-gated, write-trail\nrow — stays undoable); other entity/op combinations stay approved-\npending until the write-execution lanes widen application.",
        "tags": [
          "agent-platform"
        ]
      }
    },
    "/api/v1/agent-proposals/{id}/decline": {
      "post": {
        "operationId": "agent_proposals_decline",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DecideProposalRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentProposalView"
                }
              }
            },
            "description": ""
          },
          "403": {
            "description": "not a permitted approver"
          },
          "404": {
            "description": "not in scope"
          },
          "409": {
            "description": "proposal already decided"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/agent-proposals/{id}/decline — decide AGAINST. A declined\nproposal produces NO write at all; the row is the audit record.",
        "tags": [
          "agent-platform"
        ]
      }
    },
    "/api/v1/agent-proposals/{id}/withdraw": {
      "post": {
        "operationId": "agent_proposals_withdraw",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentProposalView"
                }
              }
            },
            "description": ""
          },
          "403": {
            "description": "only the proposing agent or an admin may withdraw"
          },
          "404": {
            "description": "not in scope"
          },
          "409": {
            "description": "proposal already decided"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/agent-proposals/{id}/withdraw — the proposing agent (or an\nadmin) cancels its own open proposal. No write ever happened.",
        "tags": [
          "agent-platform"
        ]
      }
    },
    "/api/v1/agent-skills": {
      "get": {
        "operationId": "agent_skills_list",
        "parameters": [
          {
            "description": "When present, every version of this slug (newest first) instead of\nthe latest version of each slug.",
            "in": "query",
            "name": "slug",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentSkillList"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/v1/agent-skills — latest version per slug (or one slug's history).",
        "tags": [
          "agent-platform"
        ]
      },
      "post": {
        "operationId": "agent_skills_publish",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublishSkillRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentSkillView"
                }
              }
            },
            "description": ""
          },
          "403": {
            "description": "owner/admin surface"
          },
          "422": {
            "description": "invalid slug or manifest"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/v1/agent-skills — publish a NEW version of a skill.",
        "tags": [
          "agent-platform"
        ]
      }
    },
    "/api/v1/agent-skills/{id}": {
      "get": {
        "operationId": "agent_skills_get",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgentSkillView"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/v1/agent-skills/{id} — one immutable version.",
        "tags": [
          "agent-platform"
        ]
      }
    },
    "/api/v1/alert-sources": {
      "get": {
        "operationId": "alert_sources_list",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AlertSourceList"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/alert-sources — newest-first config list (no secrets).",
        "tags": [
          "alerts"
        ]
      },
      "post": {
        "operationId": "alert_sources_create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAlertSourceRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AlertSourceMutationResponse"
                }
              }
            },
            "description": ""
          },
          "409": {
            "description": "source_ref collision or idempotency key reused"
          },
          "422": {
            "description": "validation failed"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/alert-sources — creates an ingest source, generates + seals\nits HMAC secret (returned ONCE), and writes the audit trail.\nInstant-first (IF1/IF2): idempotency-keyed, read-your-write response.",
        "tags": [
          "alerts"
        ]
      }
    },
    "/api/v1/alert-sources/{id}": {
      "patch": {
        "operationId": "alert_sources_update",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchAlertSourceRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AlertSourceMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "source not visible in scope (rls_sparse)"
          },
          "409": {
            "description": "version conflict or idempotency key reused"
          },
          "422": {
            "description": "validation failed"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PATCH /api/alert-sources/{id} — re-point the board, rename, resize the\nstorm window, or disable. Instant-first (IF1/IF2).",
        "tags": [
          "alerts"
        ]
      }
    },
    "/api/v1/alerts": {
      "get": {
        "operationId": "alerts_list",
        "parameters": [
          {
            "in": "query",
            "name": "source_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "in": "query",
            "name": "ticket_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "format": "int64",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "format": "int64",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AlertListResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/alerts — newest-first ledger browse, filterable by source and\nincident ticket (staff, ticket-view scoped).",
        "tags": [
          "alerts"
        ]
      }
    },
    "/api/v1/alerts/ingest/{source_ref}": {
      "post": {
        "description": "Responses: 200 with a terminal `status` (incident_created / collapsed /\nduplicate); 401 missing/bad signature; 403 disabled source; 404 unknown\nsource_ref; 422 malformed payload.",
        "operationId": "alerts_ingest",
        "parameters": [
          {
            "description": "Public ingest routing id of an alert source",
            "in": "path",
            "name": "source_ref",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IngestAlertRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IngestResponse"
                }
              }
            },
            "description": ""
          },
          "401": {
            "description": "missing or invalid signature"
          },
          "403": {
            "description": "alert source disabled"
          },
          "404": {
            "description": "unknown source_ref"
          },
          "422": {
            "description": "validation failed"
          }
        },
        "summary": "POST /api/alerts/ingest/{source_ref} — HMAC-verified alert ingest.",
        "tags": [
          "alerts"
        ]
      }
    },
    "/api/v1/api-keys": {
      "get": {
        "operationId": "api_keys_list",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyList"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/api-keys — listing without secrets.",
        "tags": [
          "integrations"
        ]
      },
      "post": {
        "operationId": "api_keys_create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateApiKeyRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyCreatedResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/api-keys — creates a key and returns the raw secret ONCE.",
        "tags": [
          "integrations"
        ]
      }
    },
    "/api/v1/api-keys/{id}": {
      "delete": {
        "operationId": "api_keys_revoke",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "DELETE /api/api-keys/{id} — immediate revocation (rotation story:\ncreate replacement → revoke old).",
        "tags": [
          "integrations"
        ]
      }
    },
    "/api/v1/appointment-requests": {
      "get": {
        "operationId": "appointment_requests_list",
        "parameters": [
          {
            "description": "Exact status: `pending | approved | declined | cancelled`.",
            "in": "query",
            "name": "status",
            "required": false,
            "schema": {
              "oneOf": [
                {
                  "type": "null"
                },
                {
                  "$ref": "#/components/schemas/AppointmentRequestStatus"
                }
              ]
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "format": "int64",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "format": "int64",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/AppointmentRequest"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/appointment-requests — the staff queue (optionally narrowed\nby status), newest first.",
        "tags": [
          "scheduling"
        ]
      }
    },
    "/api/v1/appointment-requests/{id}/approve": {
      "post": {
        "operationId": "appointment_requests_approve",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DecideAppointmentRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DecideResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "request not found in scope"
          },
          "409": {
            "description": "not pending, slot no longer free, double-booking backstop, version conflict, or idempotency key reused"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/appointment-requests/{id}/approve — book the requested slot\non the staff member's calendar. Re-validates availability + conflicts\nat decision time (the client's listing may be stale); a slot that\nstopped being free is a typed 409, never a wedged booking. Emits BOTH\n`appointment.created` (the booking enters the world through the\nnormal creation event) and `appointment_request.approved`.",
        "tags": [
          "scheduling"
        ]
      }
    },
    "/api/v1/appointment-requests/{id}/decline": {
      "post": {
        "operationId": "appointment_requests_decline",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DecideAppointmentRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DecideResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "request not found in scope"
          },
          "409": {
            "description": "not pending, version conflict, or idempotency key reused"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/appointment-requests/{id}/decline — refuse a pending\nrequest. No calendar effect; the note reaches the client.",
        "tags": [
          "scheduling"
        ]
      }
    },
    "/api/v1/appointments": {
      "post": {
        "operationId": "appointment_create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAppointmentRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Appointment"
                }
              }
            },
            "description": ""
          },
          "409": {
            "description": "slot already booked"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/appointments — create a booking (409 on overlap).",
        "tags": [
          "scheduling"
        ]
      }
    },
    "/api/v1/appointments/{id}": {
      "get": {
        "operationId": "appointment_get",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Appointment"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/appointments/{id} — fetch one booking in the caller's org.",
        "tags": [
          "scheduling"
        ]
      },
      "patch": {
        "operationId": "appointment_patch",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchAppointmentRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Appointment"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PATCH /api/appointments/{id} — edit fields/status (times unchanged;\nmoves use the dedicated endpoint so clients get rescheduled events).",
        "tags": [
          "scheduling"
        ]
      }
    },
    "/api/v1/appointments/{id}/cancel": {
      "post": {
        "operationId": "appointment_cancel",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Appointment"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/appointments/{id}/cancel — frees the slot (status flip, never\ndeletion, so history survives).",
        "tags": [
          "scheduling"
        ]
      }
    },
    "/api/v1/appointments/{id}/move": {
      "post": {
        "operationId": "appointment_move",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MoveAppointmentRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Appointment"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": ""
          },
          "409": {
            "description": "target slot already booked"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/appointments/{id}/move — reschedule with re-validation\n(dry-run semantics inline: a conflicting move is rejected atomically\nand emits a `rescheduled` event only when it lands).",
        "tags": [
          "scheduling"
        ]
      }
    },
    "/api/v1/attachments/{id}": {
      "delete": {
        "operationId": "attachments_delete",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AttachmentDeleted"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "DELETE /api/attachments/{id} — author-gated (the uploader, or an org\nowner/admin). The stored object is reclaimed only when no sibling row\nstill references the same content-addressed key.",
        "tags": [
          "attachments"
        ]
      }
    },
    "/api/v1/attachments/{id}/download": {
      "get": {
        "operationId": "attachments_download",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/octet-stream": {
                "schema": {
                  "items": {
                    "format": "int32",
                    "minimum": 0,
                    "type": "integer"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/attachments/{id}/download — streams the stored bytes through\nthe API behind board-view authz (no public URLs in v1). Integrity is\nverifiable against the recorded sha256 (`x-meridian-sha256` header).",
        "tags": [
          "attachments"
        ]
      }
    },
    "/api/v1/audit-events": {
      "get": {
        "operationId": "audit_list",
        "parameters": [
          {
            "description": "Legacy cursor (kept for compatibility): strictly older than this.",
            "in": "query",
            "name": "before",
            "required": false,
            "schema": {
              "format": "date-time",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Keyset cursor from a previous page's `next_cursor`.",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Actor filter: user uuid or \"system\".",
            "in": "query",
            "name": "actor",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Action prefix filter, e.g. \"auth\" matches every auth.* event.",
            "in": "query",
            "name": "action",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Inclusive lower bound on occurred_at.",
            "in": "query",
            "name": "from",
            "required": false,
            "schema": {
              "format": "date-time",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Inclusive upper bound on occurred_at.",
            "in": "query",
            "name": "to",
            "required": false,
            "schema": {
              "format": "date-time",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "format": "int64",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuditPage"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/audit-events — append-only audit trail, newest first, filterable\nby actor / action prefix / time range with opaque cursor pagination.",
        "tags": [
          "audit"
        ]
      }
    },
    "/api/v1/auth/login": {
      "post": {
        "operationId": "handlers_login",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LoginRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LoginResponse"
                }
              }
            },
            "description": ""
          },
          "401": {
            "description": "bad credentials"
          }
        },
        "summary": "POST /api/auth/login — resolves the org by email (SECURITY DEFINER\nbridge), verifies the argon2 hash under RLS scope. When any second\nfactor is enrolled, returns a short-lived `mfa_pending` bridge instead\nof tokens; POST /api/auth/mfa/verify completes it.",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/auth/logout": {
      "post": {
        "operationId": "handlers_logout",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RefreshRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": ""
          }
        },
        "summary": "POST /api/auth/logout — revokes the refresh session and audits the event.",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/auth/mfa/recovery-codes/regenerate": {
      "post": {
        "operationId": "mfa_recovery_regenerate",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RegenerateRecoveryRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecoveryCodesResponse"
                }
              }
            },
            "description": ""
          },
          "401": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/auth/mfa/recovery-codes/regenerate — invalidates all previous\ncodes, issues a new batch (revealed once).",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/auth/mfa/totp/disable": {
      "post": {
        "operationId": "mfa_totp_disable",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TotpDisableRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": ""
          },
          "401": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/auth/mfa/totp/disable — requires password AND a live factor;\nwipes TOTP enrollment and all recovery codes.",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/auth/mfa/totp/enroll-begin": {
      "post": {
        "operationId": "mfa_totp_enroll_begin",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TotpEnrollBeginResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/auth/mfa/totp/enroll-begin — generates a secret (returned ONCE)\nand stores it sealed+unconfirmed. Re-calling restarts enrollment safely.",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/auth/mfa/totp/enroll-verify": {
      "post": {
        "operationId": "mfa_totp_enroll_verify",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TotpEnrollVerifyRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RecoveryCodesResponse"
                }
              }
            },
            "description": ""
          },
          "401": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/auth/mfa/totp/enroll-verify — confirms the enrollment with the\nfirst valid code and issues the one-time recovery-code batch.",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/auth/mfa/verify": {
      "post": {
        "operationId": "mfa_verify",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MfaVerifyRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenPair"
                }
              }
            },
            "description": ""
          },
          "401": {
            "description": ""
          }
        },
        "summary": "POST /api/auth/mfa/verify — completes an MFA-gated login with a TOTP or\nrecovery code. Tries TOTP first (advancing the replay watermark), then\nfalls back to single-use recovery codes.",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/auth/mfa/webauthn/begin": {
      "post": {
        "operationId": "mfa_webauthn_login_begin",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MfaTokenRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebauthnBeginResponse"
                }
              }
            },
            "description": ""
          },
          "401": {
            "description": ""
          }
        },
        "summary": "POST /api/auth/mfa/webauthn/begin — assertion request for the pending\nMFA login. Requires a valid mfa_pending token.",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/auth/mfa/webauthn/credentials": {
      "get": {
        "operationId": "mfa_webauthn_list",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/WebauthnCredentialInfo"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/auth/mfa/webauthn/credentials — list registered passkeys.",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/auth/mfa/webauthn/credentials/{id}/remove": {
      "post": {
        "operationId": "mfa_webauthn_remove",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebauthnRemoveRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/auth/mfa/webauthn/credentials/{id}/remove — password-gated\nremoval of one passkey.",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/auth/mfa/webauthn/finish": {
      "post": {
        "operationId": "mfa_webauthn_login_finish",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebauthnLoginFinishRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenPair"
                }
              }
            },
            "description": ""
          },
          "401": {
            "description": ""
          }
        },
        "summary": "POST /api/auth/mfa/webauthn/finish — verifies the assertion and issues\nfull tokens. Ceremony state is single-use; replay of a finish call fails.",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/auth/mfa/webauthn/register/begin": {
      "post": {
        "operationId": "mfa_webauthn_register_begin",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebauthnBeginResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/auth/mfa/webauthn/register/begin — starts a passkey\nregistration for the authenticated user.",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/auth/mfa/webauthn/register/finish": {
      "post": {
        "operationId": "mfa_webauthn_register_finish",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebauthnRegisterFinishRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/auth/mfa/webauthn/register/finish — verifies the attestation\nand stores the passkey. The public key is stored; no secret exists.",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/auth/oidc/providers": {
      "get": {
        "operationId": "oidc_providers_list",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/OidcProviderInfo"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          },
          "403": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/auth/oidc/providers — admin listing. Secrets excluded by type.",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/auth/oidc/providers/public": {
      "get": {
        "operationId": "oidc_providers_public",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/PublicProvider"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "GET /api/auth/oidc/providers/public — drives config-driven SSO buttons\non the login screen. No configuration detail beyond names.",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/auth/oidc/providers/{name}": {
      "delete": {
        "operationId": "oidc_provider_delete",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": ""
          },
          "403": {
            "description": ""
          },
          "404": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "DELETE /api/auth/oidc/providers/{name}.",
        "tags": [
          "auth"
        ]
      },
      "put": {
        "operationId": "oidc_provider_upsert",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpsertProviderRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OidcProviderInfo"
                }
              }
            },
            "description": ""
          },
          "403": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PUT /api/auth/oidc/providers/{name} — create or replace a provider.\nThe client secret is required on every write (rotate-friendly).",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/auth/oidc/{name}/callback": {
      "get": {
        "operationId": "oidc_callback",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "303": {
            "description": "redirect to web app"
          }
        },
        "summary": "GET /api/auth/oidc/{name}/callback — validates state signature/expiry/\nprovider binding and nonce echo, runs the conservative decision, then\nhands tokens (or link confirmation) to the web app via a single-use code.",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/auth/oidc/{name}/link": {
      "post": {
        "operationId": "oidc_link_begin",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LinkBeginResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/auth/oidc/{name}/link — begins the EXPLICIT account-link flow\nfor the current user. Returns the authorize URL to navigate to.",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/auth/oidc/{name}/login": {
      "get": {
        "operationId": "oidc_login_redirect",
        "parameters": [
          {
            "in": "path",
            "name": "name",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "303": {
            "description": "redirect to provider"
          },
          "404": {
            "description": ""
          }
        },
        "summary": "GET /api/auth/oidc/{name}/login — 303 to the IdP with signed state,\nnonce, and PKCE S256 bound together.",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/auth/refresh": {
      "post": {
        "operationId": "handlers_refresh",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RefreshRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenPair"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "POST /api/auth/refresh — rotates the refresh secret as a NEW chain node.\nPresenting an already-consumed (rotated/revoked/expired) token proves\nreplay: the WHOLE chain is revoked and the event is audited.",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/auth/register": {
      "post": {
        "operationId": "handlers_register",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RegisterRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenPair"
                }
              }
            },
            "description": ""
          },
          "409": {
            "description": "slug or email already exists"
          },
          "422": {
            "description": "validation error"
          }
        },
        "summary": "POST /api/auth/register — creates the org, its default roles/board/SLA\npolicy, and the first user as Owner. One transaction: a half-created org\ncan never exist.",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/auth/sessions": {
      "get": {
        "operationId": "auth_sessions_list",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/SessionInfo"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/auth/sessions — the caller's live refresh sessions (security\nsettings page).",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/auth/sessions/{id}/revoke": {
      "post": {
        "operationId": "auth_session_revoke",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/auth/sessions/{id}/revoke — kills one of the caller's own\nsessions (sign-out-everywhere-else primitive).",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/automation-rules": {
      "get": {
        "operationId": "automation_rules_list",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "type": "object"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/automation-rules",
        "tags": [
          "automations"
        ]
      },
      "post": {
        "operationId": "automation_rules_create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateRuleRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/automation-rules — documents are validated through core-domain\nBEFORE storage, so stored rules are always well-formed (malformed rules\ncan only arrive out-of-band and are skipped at evaluation time).",
        "tags": [
          "automations"
        ]
      }
    },
    "/api/v1/automation-rules/{id}": {
      "delete": {
        "operationId": "automation_rules_delete",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "DELETE /api/automation-rules/{id}",
        "tags": [
          "automations"
        ]
      },
      "patch": {
        "operationId": "automation_rules_update",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateRuleRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PATCH /api/automation-rules/{id}",
        "tags": [
          "automations"
        ]
      }
    },
    "/api/v1/availability": {
      "get": {
        "operationId": "availability_list",
        "parameters": [
          {
            "description": "Whose windows. Defaults to the caller; another user requires owner/admin.",
            "in": "query",
            "name": "user_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AvailabilityListResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/availability — list one user's weekly templates.",
        "tags": [
          "scheduling"
        ]
      },
      "post": {
        "operationId": "availability_create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAvailabilityRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AvailabilityWindow"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/availability — add a weekly template for a user.",
        "tags": [
          "scheduling"
        ]
      }
    },
    "/api/v1/availability/{id}": {
      "delete": {
        "operationId": "availability_delete",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "Owner of the row being deleted (must match self-or-admin rule).",
            "in": "query",
            "name": "user_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": ""
          },
          "404": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "DELETE /api/availability/{id}?user_id= — remove one template.",
        "tags": [
          "scheduling"
        ]
      }
    },
    "/api/v1/billing/invoice-runs": {
      "get": {
        "operationId": "billing_invoice_runs_list",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/InvoiceRun"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/billing/invoice-runs — most recent runs first.",
        "tags": [
          "billing"
        ]
      },
      "post": {
        "operationId": "billing_invoice_runs_create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateInvoiceRunRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceRunResponse"
                }
              }
            },
            "description": ""
          },
          "409": {
            "description": "mixed-currency run or idempotency key reused"
          },
          "422": {
            "description": "validation failure"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/billing/invoice-runs — evaluate every billable contract over\nthe window (optionally one client's) and persist one invoice per\ncontract with at least one candidate line. Idempotency-keyed (IF1):\nthe same key with the same body replays the stored run.",
        "tags": [
          "billing"
        ]
      }
    },
    "/api/v1/billing/invoice-runs/{id}": {
      "get": {
        "operationId": "billing_invoice_runs_get",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceRun"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "run not found"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/billing/invoice-runs/{id} — one run's roll-up.",
        "tags": [
          "billing"
        ]
      }
    },
    "/api/v1/billing/preview": {
      "get": {
        "operationId": "billing_preview",
        "parameters": [
          {
            "description": "Window start (inclusive), ISO date.",
            "in": "query",
            "name": "from",
            "required": false,
            "schema": {
              "format": "date",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Window end (inclusive), ISO date.",
            "in": "query",
            "name": "to",
            "required": false,
            "schema": {
              "format": "date",
              "type": [
                "string",
                "null"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrgBillingPreview"
                }
              }
            },
            "description": ""
          },
          "422": {
            "description": "missing or inverted window"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/billing/preview — evaluate EVERY billable contract in the\norg over `[from, to]` (cancelled contracts excluded; effective windows\nmust intersect). READ-ONLY: the org-wide dry-run of a Wave-9 invoice\nrun.",
        "tags": [
          "billing"
        ]
      }
    },
    "/api/v1/board-groups": {
      "get": {
        "operationId": "board_groups_list",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/BoardGroup"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/board-groups — the org's groups in nav order (any member may\nread; rendering input for the tree).",
        "tags": [
          "boards"
        ]
      },
      "post": {
        "operationId": "board_groups_create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateGroupRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BoardGroup"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/board-groups — creates a nav group (ManageBoards gated);\nemits `board.group_created`.",
        "tags": [
          "boards"
        ]
      }
    },
    "/api/v1/board-groups/{id}": {
      "delete": {
        "operationId": "board_groups_delete",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "DELETE /api/board-groups/{id} — removes a group; member boards become\nungrouped, never deleted. ManageBoards OR the group's owner; emits\n`board.group_removed`.",
        "tags": [
          "boards"
        ]
      },
      "patch": {
        "operationId": "board_groups_update",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateGroupRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BoardGroup"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PATCH /api/board-groups/{id} — renames/reorders a group. ManageBoards\nOR the group's owner may do this; emits `board.group_updated`.",
        "tags": [
          "boards"
        ]
      }
    },
    "/api/v1/boards": {
      "get": {
        "operationId": "boards_list",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/Board"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/boards",
        "tags": [
          "boards"
        ]
      },
      "post": {
        "operationId": "boards_create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateBoardRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Board"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/boards — creates a board seeded with the four default statuses.",
        "tags": [
          "boards"
        ]
      }
    },
    "/api/v1/boards/favorite": {
      "post": {
        "operationId": "boards_toggle_favorite",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FavoriteRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/boards/favorite — toggles a board favorite for the current\nuser (user-scoped; any authenticated member may star boards they can\nsee). Emits `board.favorite_toggled` in-tx.",
        "tags": [
          "boards"
        ]
      }
    },
    "/api/v1/boards/nav": {
      "get": {
        "operationId": "boards_nav",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/BoardNavEntry"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/boards/nav — every org board annotated with the current\nuser's favorite mark, board role, and group assignment.",
        "tags": [
          "boards"
        ]
      }
    },
    "/api/v1/boards/{id}/checklist-template": {
      "delete": {
        "operationId": "boards_delete_checklist_template",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "DELETE /api/boards/{id}/checklist-template — removes the template.\nTicket instances demote to ad-hoc items; with no template left,\nclose-time enforcement is off by construction regardless of the toggle.",
        "tags": [
          "boards"
        ]
      },
      "get": {
        "operationId": "boards_get_checklist_template",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChecklistTemplateView"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/boards/{id}/checklist-template",
        "tags": [
          "boards"
        ]
      },
      "put": {
        "operationId": "boards_put_checklist_template",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PutChecklistTemplateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChecklistTemplateView"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PUT /api/boards/{id}/checklist-template — creates or replaces the\nboard's template wholesale and sets the enforcement toggle; emits\n`board.checklist_template_updated` and audits the change.",
        "tags": [
          "boards"
        ]
      }
    },
    "/api/v1/boards/{id}/fields": {
      "get": {
        "operationId": "fields_list_for_board",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/FieldDefView"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/boards/{id}/fields — active ticket definitions governing this\nboard (org-wide plus board-owned), sort-order stable.",
        "tags": [
          "fields"
        ]
      },
      "post": {
        "operationId": "fields_create_def",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateFieldDefRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FieldDefView"
                }
              }
            },
            "description": ""
          },
          "422": {
            "description": "invalid definition"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/boards/{id}/fields — creates a board-scoped definition\n(board-admin gated); emits `custom_field.def_created`.",
        "tags": [
          "fields"
        ]
      }
    },
    "/api/v1/boards/{id}/fields/{field_id}": {
      "delete": {
        "operationId": "fields_delete_def",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "field_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "DELETE /api/boards/{id}/fields/{field_id} — removes the definition and\ncascades its stored values; emits `custom_field.def_removed`.",
        "tags": [
          "fields"
        ]
      },
      "patch": {
        "operationId": "fields_update_def",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "field_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateFieldDefRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FieldDefView"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PATCH /api/boards/{id}/fields/{field_id} — partial edit of a board-owned\ndefinition. Kind is immutable (it would orphan stored values); emit\n`custom_field.def_updated` on success.",
        "tags": [
          "fields"
        ]
      }
    },
    "/api/v1/boards/{id}/group": {
      "put": {
        "operationId": "boards_assign_group",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AssignGroupRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PUT /api/boards/{id}/group — assigns/unassigns the board's nav group.\nBoard-admin gated (ConfigureBoard); emits `board.group_updated`.",
        "tags": [
          "boards"
        ]
      }
    },
    "/api/v1/boards/{id}/members": {
      "get": {
        "operationId": "boards_list_members",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/BoardMemberView"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/boards/{id}/members — the roster (ConfigureBoard gated).",
        "tags": [
          "boards"
        ]
      },
      "put": {
        "operationId": "boards_upsert_member",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpsertMemberRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BoardMemberView"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PUT /api/boards/{id}/members — adds or re-roles one membership.\nManageMembers gated (board admin); emits `board.membership_updated`.",
        "tags": [
          "boards"
        ]
      }
    },
    "/api/v1/boards/{id}/members/{user_id}": {
      "delete": {
        "operationId": "boards_remove_member",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "user_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "DELETE /api/boards/{id}/members/{user_id} — removes one membership;\nthe user falls back to org-governed access. Emits\n`board.membership_removed`.",
        "tags": [
          "boards"
        ]
      }
    },
    "/api/v1/boards/{id}/statuses": {
      "get": {
        "operationId": "boards_list_statuses",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/BoardStatus"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/boards/{id}/statuses",
        "tags": [
          "boards"
        ]
      },
      "post": {
        "operationId": "boards_add_status",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateStatusRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BoardStatus"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/boards/{id}/statuses — adds a custom status bound to a\nsemantic category; emits `board.status_added`.",
        "tags": [
          "boards"
        ]
      }
    },
    "/api/v1/boards/{id}/statuses/{status_id}": {
      "delete": {
        "operationId": "boards_delete_status",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "status_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "DELETE /api/boards/{id}/statuses/{status_id} — removes an UNUSED custom\nstatus. Tickets referencing it force a 409; the last entry status of a\nboard is protected so ticket creation can never break.",
        "tags": [
          "boards"
        ]
      },
      "patch": {
        "operationId": "boards_update_status",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "status_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateStatusRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BoardStatus"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PATCH /api/boards/{id}/statuses/{status_id} — rebinds/reorders/renames a\nstatus; emits `board.status_updated`.",
        "tags": [
          "boards"
        ]
      }
    },
    "/api/v1/boards/{id}/transitions": {
      "get": {
        "operationId": "boards_list_transitions",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BoardTransitionsResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/boards/{id}/transitions — the board's effective workflow.",
        "tags": [
          "boards"
        ]
      },
      "put": {
        "operationId": "boards_set_transitions",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetTransitionsRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BoardTransitionsResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PUT /api/boards/{id}/transitions — atomically replaces the explicit\ntransition matrix; emits `board.transitions_updated`. Endpoints must be\nstatuses of THIS board and self-transitions are rejected.",
        "tags": [
          "boards"
        ]
      }
    },
    "/api/v1/calendar-exclusions": {
      "get": {
        "operationId": "calendar_exclusion_list",
        "parameters": [
          {
            "in": "query",
            "name": "user_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "in": "query",
            "name": "from",
            "required": false,
            "schema": {
              "format": "date-time",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "in": "query",
            "name": "to",
            "required": false,
            "schema": {
              "format": "date-time",
              "type": [
                "string",
                "null"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/CalendarExclusion"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/calendar-exclusions?user_id=&from=&to=",
        "tags": [
          "scheduling"
        ]
      },
      "post": {
        "operationId": "calendar_exclusion_create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateExclusionRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CalendarExclusion"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/calendar-exclusions — record time-off.",
        "tags": [
          "scheduling"
        ]
      }
    },
    "/api/v1/calendar-exclusions/{id}": {
      "delete": {
        "operationId": "calendar_exclusion_delete",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "Owner of the row being deleted (must match self-or-admin rule).",
            "in": "query",
            "name": "user_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": ""
          },
          "404": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "DELETE /api/calendar-exclusions/{id}?user_id=",
        "tags": [
          "scheduling"
        ]
      }
    },
    "/api/v1/calendar/day": {
      "get": {
        "operationId": "calendar_day",
        "parameters": [
          {
            "description": "Whose calendar. Defaults to the caller; another user requires\nowner/admin.",
            "in": "query",
            "name": "user_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Local date in the TARGET user's timezone. Day view: the day itself.\nWeek view: any date inside the week (Monday-start). Defaults to\ntoday in that timezone.",
            "in": "query",
            "name": "date",
            "required": false,
            "schema": {
              "format": "date",
              "type": [
                "string",
                "null"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CalendarViewResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/calendar/day — one local day for one user.",
        "tags": [
          "scheduling"
        ]
      }
    },
    "/api/v1/calendar/team": {
      "get": {
        "operationId": "calendar_team",
        "parameters": [
          {
            "description": "Inclusive window start (default: today's UTC midnight minus 1 day).",
            "in": "query",
            "name": "from",
            "required": false,
            "schema": {
              "format": "date-time",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Exclusive window end (default: `from` + 8 days).",
            "in": "query",
            "name": "to",
            "required": false,
            "schema": {
              "format": "date-time",
              "type": [
                "string",
                "null"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CalendarViewResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/calendar/team — every org member over an absolute UTC range.",
        "tags": [
          "scheduling"
        ]
      }
    },
    "/api/v1/calendar/week": {
      "get": {
        "operationId": "calendar_week",
        "parameters": [
          {
            "description": "Whose calendar. Defaults to the caller; another user requires\nowner/admin.",
            "in": "query",
            "name": "user_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Local date in the TARGET user's timezone. Day view: the day itself.\nWeek view: any date inside the week (Monday-start). Defaults to\ntoday in that timezone.",
            "in": "query",
            "name": "date",
            "required": false,
            "schema": {
              "format": "date",
              "type": [
                "string",
                "null"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CalendarViewResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/calendar/week — Monday-start local week for one user.",
        "tags": [
          "scheduling"
        ]
      }
    },
    "/api/v1/clients": {
      "get": {
        "operationId": "clients_list",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/Client"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/clients",
        "tags": [
          "clients"
        ]
      },
      "post": {
        "operationId": "clients_create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateClientRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ClientMutationResponse"
                }
              }
            },
            "description": ""
          },
          "409": {
            "description": "idempotency key reused"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/clients — instant-first (IF1/IF2): idempotency-keyed and\nreturns the read-your-write `mutation` metadata.",
        "tags": [
          "clients"
        ]
      }
    },
    "/api/v1/clients/{id}": {
      "get": {
        "operationId": "clients_get_one",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Client"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/clients/{id}",
        "tags": [
          "clients"
        ]
      }
    },
    "/api/v1/clients/{id}/assets": {
      "get": {
        "operationId": "clients_list_assets",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/DeviceAsset"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/clients/{id}/assets",
        "tags": [
          "clients"
        ]
      },
      "post": {
        "operationId": "clients_create_asset",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAssetRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceAsset"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/clients/{id}/assets",
        "tags": [
          "clients"
        ]
      }
    },
    "/api/v1/clients/{id}/board-exposures": {
      "get": {
        "operationId": "board_exposures_list",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/BoardExposureView"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/clients/{id}/board-exposures — every configured row for the\nclient (exposed or not), so admin UI can render toggles.",
        "tags": [
          "portal-admin"
        ]
      },
      "put": {
        "operationId": "board_exposures_put",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PutExposureRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BoardExposureView"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "board or client missing"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PUT /api/clients/{id}/board-exposures — upsert one board×client row.",
        "tags": [
          "portal-admin"
        ]
      }
    },
    "/api/v1/clients/{id}/contacts": {
      "get": {
        "operationId": "clients_list_contacts",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/Contact"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/clients/{id}/contacts",
        "tags": [
          "clients"
        ]
      },
      "post": {
        "operationId": "clients_create_contact",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateContactRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Contact"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/clients/{id}/contacts",
        "tags": [
          "clients"
        ]
      }
    },
    "/api/v1/clients/{id}/portal-users": {
      "get": {
        "operationId": "portal_users_list",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/PortalUser"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/clients/{id}/portal-users — directory for one client.",
        "tags": [
          "portal-admin"
        ]
      },
      "post": {
        "operationId": "portal_users_create",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePortalUserRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortalUser"
                }
              }
            },
            "description": ""
          },
          "409": {
            "description": "email already provisioned"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/clients/{id}/portal-users — provision (invite) one identity.",
        "tags": [
          "portal-admin"
        ]
      }
    },
    "/api/v1/clients/{id}/sites": {
      "get": {
        "operationId": "clients_list_sites",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/Site"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/clients/{id}/sites",
        "tags": [
          "clients"
        ]
      },
      "post": {
        "operationId": "clients_create_site",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateSiteRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Site"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/clients/{id}/sites",
        "tags": [
          "clients"
        ]
      }
    },
    "/api/v1/contracts": {
      "get": {
        "operationId": "contracts_list",
        "parameters": [
          {
            "in": "query",
            "name": "client_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Exact status: `draft|active|ended|cancelled`.",
            "in": "query",
            "name": "status",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Only contracts effective on this date.",
            "in": "query",
            "name": "effective_on",
            "required": false,
            "schema": {
              "format": "date",
              "type": [
                "string",
                "null"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/Contract"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/contracts — list with optional client/status/effective-date\nfilters, ordered by contract number.",
        "tags": [
          "billing"
        ]
      },
      "post": {
        "operationId": "contracts_create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateContractRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContractMutationResponse"
                }
              }
            },
            "description": ""
          },
          "409": {
            "description": "duplicate contract number, idempotency key reused, or version conflict"
          },
          "422": {
            "description": "validation failure"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/contracts — instant-first (IF1/IF2): idempotency-keyed and\nreturns the read-your-write `mutation` metadata.",
        "tags": [
          "billing"
        ]
      }
    },
    "/api/v1/contracts/{id}": {
      "delete": {
        "operationId": "contracts_delete",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContractDetail"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "contract not visible in scope"
          },
          "409": {
            "description": "contract has invoices"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "DELETE /api/contracts/{id} — removes the contract aggregate. A typed\n404 (`rls_sparse`) means the target was never visible in scope.\nThe Wave 9 invoicing lane's billing-lock guard refuses the delete\nonce invoices reference the contract (typed 409).",
        "tags": [
          "billing"
        ]
      },
      "get": {
        "operationId": "contracts_get_one",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContractDetail"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/contracts/{id} — the contract aggregate (agreement + rate\ncard + fee schedule).",
        "tags": [
          "billing"
        ]
      },
      "patch": {
        "operationId": "contracts_patch",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchContractRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContractMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "contract not visible in scope"
          },
          "409": {
            "description": "version conflict, duplicate number, or idempotency key reused"
          },
          "422": {
            "description": "validation failure"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PATCH /api/contracts/{id} — instant-first (IF1/IF2) partial update.\nAbsent fields keep their values; `rates`/`fees`, when present,\nreplace the whole card/schedule. The version gate rejects stale\nwrites with a typed 409.",
        "tags": [
          "billing"
        ]
      }
    },
    "/api/v1/contracts/{id}/billing-preview": {
      "get": {
        "operationId": "contracts_billing_preview",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "Window start (inclusive), ISO date.",
            "in": "query",
            "name": "from",
            "required": false,
            "schema": {
              "format": "date",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Window end (inclusive), ISO date.",
            "in": "query",
            "name": "to",
            "required": false,
            "schema": {
              "format": "date",
              "type": [
                "string",
                "null"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BillingEvaluation"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "contract not found"
          },
          "422": {
            "description": "missing or inverted window"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/contracts/{id}/billing-preview — evaluate this contract's\nbilling rules over `[from, to]` and return the draft invoice-line\ncandidates. READ-ONLY: nothing persists, no billed markers exist.",
        "tags": [
          "billing"
        ]
      }
    },
    "/api/v1/dispatch-connector/appointments/{id}/status": {
      "post": {
        "operationId": "dispatch_connector_push_status",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PushStatusRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PushStatusResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "appointment not visible in scope"
          },
          "409": {
            "description": "idempotency key reused with a different payload"
          },
          "422": {
            "description": "unknown status vocabulary"
          },
          "429": {
            "description": "rate limit exceeded (Retry-After header)"
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "api_key": []
          }
        ],
        "summary": "POST /api/dispatch-connector/appointments/{id}/status — push one\nfield-service status update. Idempotent via the instant envelope: the\nsame key + payload replays the same stored row (never double-pushes);\na foreign-org appointment id is a bare 404.",
        "tags": [
          "dispatch-connector"
        ]
      }
    },
    "/api/v1/dispatch-connector/schedule": {
      "get": {
        "operationId": "dispatch_connector_schedule",
        "parameters": [
          {
            "in": "query",
            "name": "from",
            "required": false,
            "schema": {
              "format": "date",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Window length in days (1..=62, default 7).",
            "in": "query",
            "name": "days",
            "required": false,
            "schema": {
              "format": "int32",
              "minimum": 0,
              "type": [
                "integer",
                "null"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConnectorScheduleView"
                }
              }
            },
            "description": ""
          },
          "403": {
            "description": "missing dispatch:read scope (keys) or not an org admin (humans)"
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "api_key": []
          }
        ],
        "summary": "GET /api/dispatch-connector/schedule — bookings in a bounded window\nwith technician/ticket/client coordinates and the latest pushed\nfield-service status per booking.",
        "tags": [
          "dispatch-connector"
        ]
      }
    },
    "/api/v1/dispatch-connector/technicians": {
      "get": {
        "operationId": "dispatch_connector_technicians",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConnectorTechniciansView"
                }
              }
            },
            "description": ""
          },
          "403": {
            "description": "missing dispatch:read scope (keys) or not an org admin (humans)"
          }
        },
        "security": [
          {
            "bearer": []
          },
          {
            "api_key": []
          }
        ],
        "summary": "GET /api/dispatch-connector/technicians — active technicians with\ntheir current (non-expired) skills.",
        "tags": [
          "dispatch-connector"
        ]
      }
    },
    "/api/v1/dispatch/assign": {
      "post": {
        "operationId": "dispatch_assign",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AssignRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DispatchAppointment"
                }
              }
            },
            "description": ""
          },
          "409": {
            "description": "slot already booked"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/dispatch/assign — place an unassigned ticket on a\ntechnician's board: creates the booking AND flips the ticket\nassignee in one transaction.",
        "tags": [
          "scheduling"
        ]
      }
    },
    "/api/v1/dispatch/bulk-move": {
      "post": {
        "description": "Every move is re-validated against the TARGET user's live bookings\nin the union window (each moved booking vacates its old slot, so\nswaps are legal); the first violating move rejects the WHOLE batch\nwith a typed 409 naming the move index and blocking booking.",
        "operationId": "dispatch_bulk_move",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkMoveRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkMoveResponse"
                }
              }
            },
            "description": ""
          },
          "409": {
            "description": "target slot already booked (typed conflict)"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/dispatch/bulk-move — atomic batch reschedule.",
        "tags": [
          "scheduling"
        ]
      }
    },
    "/api/v1/dispatch/capacity": {
      "get": {
        "operationId": "dispatch_capacity",
        "parameters": [
          {
            "in": "query",
            "name": "from",
            "required": false,
            "schema": {
              "format": "date",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Horizon length in days (1..=31).",
            "in": "query",
            "name": "days",
            "required": false,
            "schema": {
              "format": "int32",
              "minimum": 0,
              "type": [
                "integer",
                "null"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CapacityHorizonView"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/dispatch/capacity — multi-day capacity horizon: the day view's\ncapacity math repeated per UTC day over the window, one org-wide\navailability read + one exclusion read + one appointment read.",
        "tags": [
          "scheduling"
        ]
      }
    },
    "/api/v1/dispatch/day": {
      "get": {
        "operationId": "dispatch_day",
        "parameters": [
          {
            "description": "The day to assemble; defaults to today (UTC).",
            "in": "query",
            "name": "date",
            "required": false,
            "schema": {
              "format": "date",
              "type": [
                "string",
                "null"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DispatchDayView"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/dispatch/day — the whole board for one day.",
        "tags": [
          "scheduling"
        ]
      }
    },
    "/api/v1/dispatch/match": {
      "get": {
        "operationId": "dispatch_match",
        "parameters": [
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "format": "int64",
              "type": [
                "integer",
                "null"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MatchView"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/dispatch/match — for every unassigned open ticket carrying\nrequired skills, the active technicians sorted best-first by how many\nrequired skills they are missing (0 = fully qualified). Expired\ncertifications never count as held.",
        "tags": [
          "scheduling"
        ]
      }
    },
    "/api/v1/dispatch/queue": {
      "get": {
        "operationId": "dispatch_queue_list",
        "parameters": [
          {
            "description": "Page size, clamped to [1, 500].",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "format": "int64",
              "type": [
                "integer",
                "null"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DispatchQueueView"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/dispatch/queue — the full unassigned queue with dispatcher\noverrides applied: overridden tickets sort by explicit rank first\n(ties fall back to the computed order), then everything else in the\ncomputed order (priority rank, then effective SLA/due deadline).",
        "tags": [
          "scheduling"
        ]
      }
    },
    "/api/v1/dispatch/queue/{ticket_id}": {
      "delete": {
        "operationId": "dispatch_queue_clear",
        "parameters": [
          {
            "in": "path",
            "name": "ticket_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QueueMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "ticket not visible"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "DELETE /api/dispatch/queue/{ticket_id} — clear a rank override.\nIdempotent: clearing an unset override still returns 200 with\n`cleared: false` (the dispatcher's intent is already satisfied).",
        "tags": [
          "scheduling"
        ]
      },
      "put": {
        "operationId": "dispatch_queue_set",
        "parameters": [
          {
            "in": "path",
            "name": "ticket_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetQueueRankRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QueueMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "ticket not visible or not open/unassigned"
          },
          "409": {
            "description": "version conflict or idempotency key reused"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PUT /api/dispatch/queue/{ticket_id} — pin a ticket's queue position.\nThe ticket must exist and still be open+unassigned (an override for a\nplaced ticket is meaningless); idempotent via the instant envelope.",
        "tags": [
          "scheduling"
        ]
      }
    },
    "/api/v1/dispatch/skills": {
      "get": {
        "operationId": "dispatch_skills_catalog",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SkillsCatalogView"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/dispatch/skills — the org's skill/certification catalog.",
        "tags": [
          "scheduling"
        ]
      }
    },
    "/api/v1/dispatch/tickets/{ticket_id}/required-skills": {
      "put": {
        "operationId": "dispatch_ticket_skills_replace",
        "parameters": [
          {
            "in": "path",
            "name": "ticket_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReplaceTicketSkillsRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TicketSkillsMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "ticket not visible in scope (rls_sparse)"
          },
          "409": {
            "description": "version conflict or idempotency key reused"
          },
          "422": {
            "description": "validation failed (labels, duplicates, count)"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PUT /api/dispatch/tickets/{ticket_id}/required-skills — full-replace\nthe job's required-skill set. The ticket must exist and be open +\nunassigned (requirements on placed work are history, not planning).",
        "tags": [
          "scheduling"
        ]
      }
    },
    "/api/v1/dispatch/travel-drafts": {
      "get": {
        "operationId": "dispatch_travel_draft_list",
        "parameters": [
          {
            "in": "query",
            "name": "user_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "`draft` | `submitted`.",
            "in": "query",
            "name": "status",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Page size, clamped to [1, 200].",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "format": "int64",
              "type": [
                "integer",
                "null"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/TravelDraftView"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/dispatch/travel-drafts — the caller's drafts (all users for\nowner/admin via `user_id`), newest first.",
        "tags": [
          "scheduling"
        ]
      },
      "post": {
        "operationId": "dispatch_travel_draft_create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTravelDraftRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TravelDraftMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "ticket not visible in scope (rls_sparse)"
          },
          "409": {
            "description": "version conflict or idempotency key reused"
          },
          "422": {
            "description": "validation failed"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/dispatch/travel-drafts — a draft mileage row against a\nticket. Instant-first (IF1/IF2): idempotency-keyed, version-gated,\nwrite-trailed.",
        "tags": [
          "scheduling"
        ]
      }
    },
    "/api/v1/dispatch/travel-drafts/{id}": {
      "delete": {
        "operationId": "dispatch_travel_draft_delete",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TravelDraftMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "not visible, or already submitted"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "DELETE /api/dispatch/travel-drafts/{id} — discard a draft. Submitted\ndrafts are immutable history (delete the TIME ENTRY through invoicing\ncorrections, never the draft's backlink).",
        "tags": [
          "scheduling"
        ]
      },
      "patch": {
        "operationId": "dispatch_travel_draft_patch",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchTravelDraftRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TravelDraftMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "not visible, or already submitted"
          },
          "409": {
            "description": "version conflict or idempotency key reused"
          },
          "422": {
            "description": "validation failed"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PATCH /api/dispatch/travel-drafts/{id} — edit a draft. Submitted\ndrafts are frozen (the time entry already exists).",
        "tags": [
          "scheduling"
        ]
      }
    },
    "/api/v1/dispatch/travel-drafts/{id}/submit": {
      "post": {
        "operationId": "dispatch_travel_draft_submit",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubmitTravelDraftRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimeEntryMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "draft not visible in scope (rls_sparse)"
          },
          "409": {
            "description": "already submitted, version conflict, or idempotency key reused"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/dispatch/travel-drafts/{id}/submit — convert a draft into a\nreal time entry through the EXISTING time-entry path\n(`insert_time_entry` + the `time_entry.created` event), then freeze\nthe draft with the entry backlink. The entry's notes carry the\nmachine-readable provenance marker (`travel_draft:<id>`); the write\ntrail records the full before/after so \"who did this\" and undo stay\nqueryable. Idempotent: the same submit replays the SAME entry.",
        "tags": [
          "scheduling"
        ]
      }
    },
    "/api/v1/dispatch/users/{user_id}/skills": {
      "put": {
        "operationId": "dispatch_user_skills_replace",
        "parameters": [
          {
            "in": "path",
            "name": "user_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReplaceUserSkillsRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserSkillsMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "user not visible in scope"
          },
          "409": {
            "description": "version conflict or idempotency key reused"
          },
          "422": {
            "description": "validation failed (labels, expiry, duplicates)"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PUT /api/dispatch/users/{user_id}/skills — full-replace the\ntechnician's skill set. The technician must be an active member of\nthis org.",
        "tags": [
          "scheduling"
        ]
      }
    },
    "/api/v1/documents": {
      "get": {
        "operationId": "documents_list",
        "parameters": [
          {
            "description": "Title substring narrowing; ranked full-text search rides /api/search.",
            "in": "query",
            "name": "q",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/Document"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/documents",
        "tags": [
          "documents"
        ]
      },
      "post": {
        "operationId": "documents_create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateDocumentRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentMutationResponse"
                }
              }
            },
            "description": ""
          },
          "409": {
            "description": "idempotency key reused"
          },
          "422": {
            "description": "title/body rejected by document rules"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/documents — instant-first (IF1/IF2); creates the document and\nits immutable version 1 in one commit.",
        "tags": [
          "documents"
        ]
      }
    },
    "/api/v1/documents/{id}": {
      "get": {
        "operationId": "documents_get",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentView"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "document not visible in scope"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/documents/{id}",
        "tags": [
          "documents"
        ]
      },
      "patch": {
        "operationId": "documents_update",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateDocumentRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "document not visible in scope"
          },
          "409": {
            "description": "version conflict or idempotency key reused"
          },
          "422": {
            "description": "title/body rejected by document rules"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PATCH /api/documents/{id} — instant-first (IF1/IF2); an edit APPENDS\nthe next immutable version and moves the document's head to it. No\nexisting version row is touched.",
        "tags": [
          "documents"
        ]
      }
    },
    "/api/v1/documents/{id}/restore": {
      "post": {
        "operationId": "documents_restore",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RestoreDocumentRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "document or restore target not visible in scope"
          },
          "409": {
            "description": "version conflict or idempotency key reused"
          },
          "422": {
            "description": "restore rejected by document rules"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/documents/{id}/restore — instant-first (IF1/IF2); §6 rule:\nthe restore APPENDS a new version copying the target's content. The\ntarget's title comes along, renames after it are not silently undone.",
        "tags": [
          "documents"
        ]
      }
    },
    "/api/v1/documents/{id}/versions": {
      "get": {
        "operationId": "documents_list_versions",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/DocumentVersion"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "document not visible in scope"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/documents/{id}/versions — the full immutable history, newest\nfirst, complete bodies included so any pair is diffable.",
        "tags": [
          "documents"
        ]
      }
    },
    "/api/v1/documents/{id}/versions/{version}": {
      "get": {
        "operationId": "documents_get_version",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "version",
            "required": true,
            "schema": {
              "format": "int32",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentVersion"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "document or version not visible in scope"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/documents/{id}/versions/{version} — one immutable snapshot.",
        "tags": [
          "documents"
        ]
      }
    },
    "/api/v1/imports/batches": {
      "get": {
        "operationId": "imports_list_batches",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/BatchViewResponse"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/imports/batches",
        "tags": [
          "imports"
        ]
      },
      "post": {
        "operationId": "imports_create_batch",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateBatchRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchCreatedResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/imports/batches",
        "tags": [
          "imports"
        ]
      }
    },
    "/api/v1/imports/batches/{batch_id}": {
      "get": {
        "operationId": "imports_get_batch",
        "parameters": [
          {
            "in": "path",
            "name": "batch_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchViewResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/imports/batches/{id}",
        "tags": [
          "imports"
        ]
      }
    },
    "/api/v1/imports/batches/{batch_id}/chunks": {
      "post": {
        "operationId": "imports_post_chunk",
        "parameters": [
          {
            "in": "path",
            "name": "batch_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChunkRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RunReportResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/imports/batches/{id}/chunks — plans then executes ONE chunk\natomically. A fail-policy chunk with any conflict persists nothing and\nreturns 409 with the full per-row report.",
        "tags": [
          "imports"
        ]
      }
    },
    "/api/v1/imports/batches/{batch_id}/finish": {
      "post": {
        "operationId": "imports_finish_batch",
        "parameters": [
          {
            "in": "path",
            "name": "batch_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BatchViewResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/imports/batches/{id}/finish — closes the span, emits\n`import.batch_finished`, and records cumulative counters in audit.",
        "tags": [
          "imports"
        ]
      }
    },
    "/api/v1/imports/batches/{batch_id}/run": {
      "post": {
        "operationId": "imports_run_batch",
        "parameters": [
          {
            "in": "path",
            "name": "batch_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RunBatchResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/imports/batches/{id}/run — hands the staged batch to the\nworker queue exactly once (generalized 2.7 job queue). Re-running a\nfinished or queued batch is a typed 409; the worker replays chunks\nidempotently through the SAME commit path as synchronous pushes.",
        "tags": [
          "imports"
        ]
      }
    },
    "/api/v1/imports/batches/{batch_id}/stage": {
      "post": {
        "operationId": "imports_stage_chunk",
        "parameters": [
          {
            "in": "path",
            "name": "batch_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StageChunkRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StageChunkResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/imports/batches/{id}/stage — uploads ONE chunk of rows to the\nObjectStore under a deterministic key WITHOUT executing anything. An\noptional saved template is applied at stage time so the stored chunk is\nalready canonical; the worker later replays the staged sequence.",
        "tags": [
          "imports"
        ]
      }
    },
    "/api/v1/imports/dry-run": {
      "post": {
        "operationId": "imports_dry_run",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DryRunRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RunReportResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/imports/dry-run",
        "tags": [
          "imports"
        ]
      }
    },
    "/api/v1/imports/templates": {
      "get": {
        "operationId": "imports_list_templates",
        "parameters": [
          {
            "description": "Narrow to one source system",
            "in": "query",
            "name": "source_system",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/TemplateViewResponse"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/imports/templates",
        "tags": [
          "imports"
        ]
      },
      "post": {
        "operationId": "imports_create_template",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTemplateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TemplateViewResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/imports/templates — saves one reusable source→canonical column\nmapping. Targets are validated against the canonical field catalog for\nthe entity kind; duplicates per (org, source system, kind, name) are a\ntyped 409.",
        "tags": [
          "imports"
        ]
      }
    },
    "/api/v1/imports/templates/{template_id}": {
      "delete": {
        "operationId": "imports_delete_template",
        "parameters": [
          {
            "in": "path",
            "name": "template_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TemplateViewResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "DELETE /api/imports/templates/{id}",
        "tags": [
          "imports"
        ]
      },
      "get": {
        "operationId": "imports_get_template",
        "parameters": [
          {
            "in": "path",
            "name": "template_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TemplateViewResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/imports/templates/{id}",
        "tags": [
          "imports"
        ]
      },
      "put": {
        "operationId": "imports_update_template",
        "parameters": [
          {
            "in": "path",
            "name": "template_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTemplateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TemplateViewResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PUT /api/imports/templates/{id} — content update; uniqueness conflicts\n(renaming onto an existing sibling) surface as typed 409s.",
        "tags": [
          "imports"
        ]
      }
    },
    "/api/v1/internal/effects": {
      "post": {
        "operationId": "internal_effects",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EffectsRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "POST /api/internal/effects — applies automation-rule effects to one\nticket through the SAME write paths users go through (ticket patch,\ncomment insert, notification fan-out), emitting every corresponding\ndomain event tagged `via_automation` so evaluators never loop.",
        "tags": [
          "automations"
        ]
      }
    },
    "/api/v1/internal/sla/verdict": {
      "post": {
        "operationId": "internal_sla_verdict",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SlaVerdictRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VerdictResponse"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "POST /api/internal/sla/verdict — fire-once application of one ladder\nstep: ledger insert (PK-guarded), breach flip, notification fan-out with\npreference gates, events + audit, all in ONE transaction.",
        "tags": [
          "sla"
        ]
      }
    },
    "/api/v1/invoices": {
      "get": {
        "operationId": "invoices_list",
        "parameters": [
          {
            "in": "query",
            "name": "client_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "in": "query",
            "name": "contract_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Exact status: `draft|issued|paid|void`.",
            "in": "query",
            "name": "status",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Exact dunning state:\n`none|reminder_sent|overdue|final_notice|collections`.",
            "in": "query",
            "name": "dunning_state",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/Invoice"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/invoices — list with client/contract/status/dunning filters.",
        "tags": [
          "billing"
        ]
      }
    },
    "/api/v1/invoices/{id}": {
      "get": {
        "operationId": "invoices_get_one",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceDetail"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "invoice not found"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/invoices/{id} — the invoice aggregate (document, lines,\npayment receipts).",
        "tags": [
          "billing"
        ]
      }
    },
    "/api/v1/invoices/{id}/document": {
      "get": {
        "operationId": "invoices_document",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "invoice not found"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/invoices/{id}/document — the print-ready HTML invoice\ndocument (print-to-PDF from any browser; v1 ships no PDF binary\noutput — see TASKLIST).",
        "tags": [
          "billing"
        ]
      }
    },
    "/api/v1/invoices/{id}/dunning": {
      "post": {
        "operationId": "invoices_dunning_transition",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DunningTransitionRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "invoice not visible in scope"
          },
          "409": {
            "description": "invoice not issuable, version conflict, or idempotency key reused"
          },
          "422": {
            "description": "backwards or same-state transition"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/invoices/{id}/dunning — move an ISSUED invoice's dunning\nstate forward (none → reminder_sent → overdue → final_notice →\ncollections; skipping rungs is allowed, backwards is refused).\nStates are data: the write emits `invoice.dunning_changed` and lands\nin the write trail. Instant-first gated (IF1/IF2).",
        "tags": [
          "billing"
        ]
      }
    },
    "/api/v1/invoices/{id}/payments": {
      "get": {
        "operationId": "invoices_payments_list",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/InvoicePayment"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "invoice not found"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/invoices/{id}/payments — the payment receipts.",
        "tags": [
          "billing"
        ]
      },
      "post": {
        "operationId": "invoices_payments_create",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RecordPaymentRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "invoice not visible in scope"
          },
          "409": {
            "description": "invoice not payable, overpayment, version conflict, or idempotency key reused"
          },
          "422": {
            "description": "validation failure"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/invoices/{id}/payments — record a payment through the\n`PaymentProvider` seam. The charge runs INSIDE the mutation\ntransaction so receipt, payment row, and invoice status commit (or\nroll back) atomically. Instant-first gated (IF1/IF2).",
        "tags": [
          "billing"
        ]
      }
    },
    "/api/v1/invoices/{id}/void": {
      "post": {
        "operationId": "invoices_void",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VoidInvoiceRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvoiceMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "invoice not visible in scope"
          },
          "409": {
            "description": "invoice not voidable, version conflict, or idempotency key reused"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/invoices/{id}/void — withdraw an ISSUED invoice. Terminal:\nconsumption markers stay, so re-running the window can never\ndouble-bill. Instant-first gated (IF1/IF2).",
        "tags": [
          "billing"
        ]
      }
    },
    "/api/v1/kb/articles": {
      "get": {
        "operationId": "kb_list_articles",
        "parameters": [
          {
            "in": "query",
            "name": "category_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "in": "query",
            "name": "status",
            "required": false,
            "schema": {
              "oneOf": [
                {
                  "type": "null"
                },
                {
                  "$ref": "#/components/schemas/KbArticleStatus"
                }
              ]
            }
          },
          {
            "description": "Only articles passing the effective client-facing gate.",
            "in": "query",
            "name": "client_visible",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "description": "Title substring narrowing; ranked full-text search rides /api/search.",
            "in": "query",
            "name": "q",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/KbArticle"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/kb/articles",
        "tags": [
          "kb"
        ]
      },
      "post": {
        "operationId": "kb_create_article",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateArticleRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ArticleMutationResponse"
                }
              }
            },
            "description": ""
          },
          "409": {
            "description": "slug already in use or idempotency key reused"
          },
          "422": {
            "description": "title/body rejected by KB rules"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/kb/articles — instant-first (IF1/IF2).",
        "tags": [
          "kb"
        ]
      }
    },
    "/api/v1/kb/articles/{id}": {
      "delete": {
        "operationId": "kb_delete_article",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": ""
          },
          "404": {
            "description": "article not visible in scope"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "DELETE /api/kb/articles/{id} — emits `kb_article.deleted` so the\nunified-search indexer drops the article's index entry.",
        "tags": [
          "kb"
        ]
      },
      "get": {
        "operationId": "kb_get_article",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KbArticle"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "article not visible in scope"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/kb/articles/{id}",
        "tags": [
          "kb"
        ]
      },
      "patch": {
        "operationId": "kb_update_article",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateArticleRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ArticleMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "article not visible in scope"
          },
          "409": {
            "description": "archived content lock, version conflict, slug reuse, or idempotency key reused"
          },
          "422": {
            "description": "title/body rejected by KB rules"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PATCH /api/kb/articles/{id} — instant-first (IF1/IF2). Archived\narticles refuse title/body edits until unarchived (typed conflict);\nstatus flips stay legal.",
        "tags": [
          "kb"
        ]
      }
    },
    "/api/v1/kb/categories": {
      "get": {
        "operationId": "kb_list_categories",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/KbCategory"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/kb/categories",
        "tags": [
          "kb"
        ]
      },
      "post": {
        "operationId": "kb_create_category",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCategoryRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CategoryMutationResponse"
                }
              }
            },
            "description": ""
          },
          "409": {
            "description": "slug already in use or idempotency key reused"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/kb/categories — instant-first (IF1/IF2).",
        "tags": [
          "kb"
        ]
      }
    },
    "/api/v1/kb/categories/{id}": {
      "delete": {
        "operationId": "kb_delete_category",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {}
              }
            },
            "description": ""
          },
          "404": {
            "description": "category not visible in scope"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "DELETE /api/kb/categories/{id} — articles keep existing (category_id\nclears; ON DELETE SET NULL), so no content is lost behind a removal.",
        "tags": [
          "kb"
        ]
      },
      "patch": {
        "operationId": "kb_update_category",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCategoryRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CategoryMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "category not visible in scope"
          },
          "409": {
            "description": "version conflict, slug reuse, or idempotency key reused"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PATCH /api/kb/categories/{id} — instant-first (IF1/IF2).",
        "tags": [
          "kb"
        ]
      }
    },
    "/api/v1/mcp/capabilities": {
      "get": {
        "operationId": "mcp_capabilities_list",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CapabilityGrantList"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/v1/mcp/capabilities — every granted capability of the org.",
        "tags": [
          "agent-platform"
        ]
      },
      "put": {
        "operationId": "mcp_capability_put",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PutCapabilityRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CapabilityGrantView"
                }
              }
            },
            "description": ""
          },
          "403": {
            "description": "owner/admin surface"
          },
          "422": {
            "description": "invalid capability or dial position"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PUT /api/v1/mcp/capabilities — grant or re-dial one capability.",
        "tags": [
          "agent-platform"
        ]
      }
    },
    "/api/v1/mcp/capabilities/{capability}": {
      "delete": {
        "operationId": "mcp_capability_revoke",
        "parameters": [
          {
            "in": "path",
            "name": "capability",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "DELETE /api/v1/mcp/capabilities/{capability} — revoke (deny again).",
        "tags": [
          "agent-platform"
        ]
      }
    },
    "/api/v1/me": {
      "get": {
        "operationId": "handlers_me",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MeResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/me — the authenticated principal with resolved permissions.",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/migration/pull/{family}": {
      "get": {
        "operationId": "migration_pull",
        "parameters": [
          {
            "description": "Entity family: client, site, contact, board, ticket, time_entry, kb_category, kb_article",
            "in": "path",
            "name": "family",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Opaque keyset cursor from a previous page's `next_cursor` (the last\nrow id). Absent = start of the family.",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Page size, clamped to [1, 200] (default 100).",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "format": "int64",
              "type": [
                "integer",
                "null"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PullPage"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/migration/pull/{family} — stateless cursor-paged export of one\nentity family: internal id + stable external key + the canonical\nimport projection. Keyset-paged on the uuidv7 id (creation order), so\npages never skip or repeat rows under concurrent writes.",
        "tags": [
          "migration"
        ]
      }
    },
    "/api/v1/migration/push/sessions": {
      "post": {
        "operationId": "migration_create_push_session",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePushSessionRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PushSessionCreated"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/migration/push/sessions — opens a connector push session over\na fresh D2 import batch. One session targets exactly one entity kind;\ncross-family ordering is the tool's run script's job (the D2 import\norder: client → site → contact → board → ticket → time entry).",
        "tags": [
          "migration"
        ]
      }
    },
    "/api/v1/migration/push/sessions/{session_id}": {
      "get": {
        "operationId": "migration_get_push_session",
        "parameters": [
          {
            "in": "path",
            "name": "session_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PushSessionView"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/migration/push/sessions/{id} — the resume view: where the\ncheckpoint stands and which chunks committed.",
        "tags": [
          "migration"
        ]
      }
    },
    "/api/v1/migration/push/sessions/{session_id}/chunks": {
      "post": {
        "operationId": "migration_push_chunk",
        "parameters": [
          {
            "in": "path",
            "name": "session_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PushChunkRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PushChunkResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/migration/push/sessions/{id}/chunks — plans then executes ONE\nchunk through the D2 commit path, then stamps the checkpoint. A\nfail-policy chunk with any conflict persists nothing and returns the\ntyped 409 with the full per-row report (checkpoint untouched — fix the\nrows and re-send the same index).",
        "tags": [
          "migration"
        ]
      }
    },
    "/api/v1/migration/push/sessions/{session_id}/finish": {
      "post": {
        "operationId": "migration_finish_push_session",
        "parameters": [
          {
            "in": "path",
            "name": "session_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PushSessionFinishedResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/migration/push/sessions/{id}/finish — closes the session and\nits D2 batch, emitting BOTH the engine lifecycle event\n(`import.batch_finished`) and the connector-level\n`migration.push_session_finished`.",
        "tags": [
          "migration"
        ]
      }
    },
    "/api/v1/notification-preferences": {
      "get": {
        "operationId": "notification_prefs_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/PreferenceView"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/notification-preferences — the caller's effective preference\nfor every kind (defaults-first resolution applied).",
        "tags": [
          "notifications"
        ]
      },
      "put": {
        "operationId": "notification_prefs_update",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdatePreferenceRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PreferenceView"
                }
              }
            },
            "description": ""
          },
          "422": {
            "description": "invalid quiet-hours window or timezone"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PUT /api/notification-preferences — upserts the caller's override row\nfor one kind and emits `notification_prefs.updated`. Quiet hours\nvalidate as a paired `HH:MM` window in a real IANA timezone;\nvalidation errors return 422.",
        "tags": [
          "notifications"
        ]
      }
    },
    "/api/v1/notifications": {
      "get": {
        "operationId": "notifications_list",
        "parameters": [
          {
            "in": "query",
            "name": "unread_only",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "format": "int64",
              "type": "integer"
            }
          },
          {
            "description": "Opaque keyset cursor from a previous page's `next_cursor`.",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotificationPage"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/notifications — the caller's notifications, newest first,\nkeyset-paginated.",
        "tags": [
          "notifications"
        ]
      }
    },
    "/api/v1/notifications/mark-read": {
      "post": {
        "operationId": "notifications_mark_read_bulk",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MarkReadBulkRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MarkReadResult"
                }
              }
            },
            "description": ""
          },
          "422": {
            "description": "empty or oversized id list"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/notifications/mark-read — bulk variant; unknown and\nalready-read ids are skipped (idempotent).",
        "tags": [
          "notifications"
        ]
      }
    },
    "/api/v1/notifications/read-all": {
      "post": {
        "operationId": "notifications_mark_all_read",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MarkReadResult"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/notifications/read-all — empties the unread badge.",
        "tags": [
          "notifications"
        ]
      }
    },
    "/api/v1/notifications/unread-count": {
      "get": {
        "operationId": "notifications_unread_count",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UnreadCount"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/notifications/unread-count",
        "tags": [
          "notifications"
        ]
      }
    },
    "/api/v1/notifications/{id}/read": {
      "post": {
        "operationId": "notifications_mark_read",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/notifications/{id}/read — marks one notification read and\nemits `notification.read` for cross-session badge sync.",
        "tags": [
          "notifications"
        ]
      }
    },
    "/api/v1/on-call-blocks": {
      "get": {
        "operationId": "on_call_list",
        "parameters": [
          {
            "description": "Whose calendar. Defaults to the caller; another user requires\nowner/admin.",
            "in": "path",
            "name": "user_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Local date in the TARGET user's timezone. Day view: the day itself.\nWeek view: any date inside the week (Monday-start). Defaults to\ntoday in that timezone.",
            "in": "path",
            "name": "date",
            "required": true,
            "schema": {
              "format": "date",
              "type": [
                "string",
                "null"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/OnCallBlock"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/on-call-blocks?user_id=&from=&to=",
        "tags": [
          "scheduling"
        ]
      },
      "post": {
        "operationId": "on_call_create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateOnCallRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OnCallBlock"
                }
              }
            },
            "description": ""
          },
          "409": {
            "description": "overlapping rotation"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/on-call-blocks — add a rotation segment (409 when stacking).",
        "tags": [
          "scheduling"
        ]
      }
    },
    "/api/v1/on-call-blocks/{id}": {
      "delete": {
        "operationId": "on_call_delete",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "Owner of the row being deleted (must match self-or-admin rule).",
            "in": "query",
            "name": "user_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": ""
          },
          "404": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "DELETE /api/on-call-blocks/{id}?user_id=",
        "tags": [
          "scheduling"
        ]
      }
    },
    "/api/v1/org": {
      "get": {
        "operationId": "org_profile_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrgProfileResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/org — profile fields shown on General settings / the wizard.",
        "tags": [
          "settings"
        ]
      },
      "patch": {
        "operationId": "org_profile_patch",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchOrgRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrgProfileResponse"
                }
              }
            },
            "description": ""
          },
          "422": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PATCH /api/org — updates name and/or ticket prefix (Admin:edit).\nIdempotent; emits `org.updated` + audit row.",
        "tags": [
          "settings"
        ]
      }
    },
    "/api/v1/org/exports": {
      "post": {
        "operationId": "org_export_create",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExportCreatedResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/org/exports — builds the versioned bundle, streams it into\nthe ObjectStore, and returns the signed download link.",
        "tags": [
          "org"
        ]
      }
    },
    "/api/v1/org/exports/{org_id}/{export_id}/download": {
      "get": {
        "operationId": "org_export_download",
        "parameters": [
          {
            "in": "path",
            "name": "org_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "export_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ExportBundle"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "GET /api/org/exports/{org_id}/{export_id}/download — streams the stored\nbundle. Authenticated by the signed link alone (no JWT): an expired or\nforged token is an unauthorized request, indistinguishable between the\ntwo. The org id is IN the path (and inside the signature) so a token\nauthorizes exactly one (org, export, expiry) triple.",
        "tags": [
          "org"
        ]
      }
    },
    "/api/v1/org/manifest": {
      "get": {
        "description": "Owner/admin gated (policy §5: the manifest is an org-level\nadministrative artifact; technicians and dispatchers have no business\nreading the full customization inventory, e.g. webhook URLs).",
        "operationId": "org_manifest",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomizationManifest"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/org/manifest — the org's customization manifest.",
        "tags": [
          "org"
        ]
      }
    },
    "/api/v1/portal-users/{id}": {
      "delete": {
        "operationId": "portal_users_delete",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          },
          "404": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "DELETE /api/portal-users/{id} — hard removal (sessions cascade). Prefer\nPATCH status=disabled to preserve history.",
        "tags": [
          "portal-admin"
        ]
      },
      "patch": {
        "operationId": "portal_users_patch",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchPortalUserRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortalUser"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PATCH /api/portal-users/{id} — rename / re-tier / enable / disable /\nreset password.",
        "tags": [
          "portal-admin"
        ]
      }
    },
    "/api/v1/portal/appointment-requests": {
      "get": {
        "operationId": "portal_list_appointment_requests",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/AppointmentRequest"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/portal/appointment-requests — the caller's OWN requests,\nnewest first.",
        "tags": [
          "portal"
        ]
      },
      "post": {
        "operationId": "portal_create_appointment_request",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PortalCreateAppointmentRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortalAppointmentRequestMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "requested staff member not found"
          },
          "409": {
            "description": "idempotency key reused"
          },
          "422": {
            "description": "validation failure (span, lead time, or slot outside published availability)"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/portal/appointment-requests — ask for a slot on a staff\nmember's calendar. The slot must be FULLY inside one free interval of\nthat staff member's PUBLISHED availability (windows minus time-off\nminus bookings) — requests are intents, so several clients may hold\noverlapping pending requests; the staff approval is the single point\nthat books the calendar (and re-validates everything).",
        "tags": [
          "portal"
        ]
      }
    },
    "/api/v1/portal/appointment-requests/{id}/cancel": {
      "post": {
        "operationId": "portal_cancel_appointment_request",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PortalCancelRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortalAppointmentRequestMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "request not owned by this portal identity"
          },
          "409": {
            "description": "request is not pending, version conflict, or idempotency key reused"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/portal/appointment-requests/{id}/cancel — the requester\nwithdraws their own still-pending request. Terminal; decided requests\ncannot be cancelled here (staff owns the calendar once decided).",
        "tags": [
          "portal"
        ]
      }
    },
    "/api/v1/portal/invoices": {
      "get": {
        "operationId": "portal_list_invoices",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/PortalInvoice"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/portal/invoices — the caller's client's invoices (issued and\npaid only), newest issued first.",
        "tags": [
          "portal"
        ]
      }
    },
    "/api/v1/portal/invoices/{id}": {
      "get": {
        "operationId": "portal_get_invoice",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortalInvoiceDetail"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/portal/invoices/{id} — one of the caller's client's invoices\nwith lines and payment receipts. Another client's document (or a\nvoided one) is a 404, indistinguishable from absent.",
        "tags": [
          "portal"
        ]
      }
    },
    "/api/v1/portal/invoices/{id}/document": {
      "get": {
        "operationId": "portal_invoice_document",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/portal/invoices/{id}/document — the SAME print-ready HTML\ndocument staff print (shared renderer), client-scoped: another\nclient's (or a void) invoice is a plain 404.",
        "tags": [
          "portal"
        ]
      }
    },
    "/api/v1/portal/invoices/{id}/pay": {
      "post": {
        "operationId": "portal_pay_invoice",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PortalPayRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortalPayResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "invoice not visible to this client"
          },
          "409": {
            "description": "invoice not payable, overpayment, version conflict, or idempotency key reused"
          },
          "422": {
            "description": "validation failure"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/portal/invoices/{id}/pay — record a payment through the\n`PaymentProvider` seam from the portal. v1 resolves the built-in\nnone-mode provider: NOTHING is charged externally; the receipt\n(\"ledger-only\") records that the client settled the amount — the UI\npresents it exactly that way. Provenance: the payment row keeps\n`created_by = NULL` (portal identities are not staff rows), the audit\nrow and the write trail carry the caller's portal actor kind.",
        "tags": [
          "portal"
        ]
      }
    },
    "/api/v1/portal/kb/articles": {
      "get": {
        "operationId": "portal_list_kb_articles",
        "parameters": [
          {
            "in": "query",
            "name": "category_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "format": "int64",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "format": "int64",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/KbArticle"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/portal/kb/articles — published client-facing articles\n(optionally narrowed to one visible category), gated by the effective\nclient-facing rule in the query.",
        "tags": [
          "portal"
        ]
      }
    },
    "/api/v1/portal/kb/articles/{id}": {
      "get": {
        "operationId": "portal_get_kb_article",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KbArticle"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/portal/kb/articles/{id} — one client-gated article; a draft,\narchived, unflagged, or foreign article is a plain 404.",
        "tags": [
          "portal"
        ]
      }
    },
    "/api/v1/portal/kb/categories": {
      "get": {
        "operationId": "portal_kb_categories",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/KbCategory"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/portal/kb/categories — the client-visible category tree.",
        "tags": [
          "portal"
        ]
      }
    },
    "/api/v1/portal/kb/search": {
      "get": {
        "operationId": "portal_kb_search",
        "parameters": [
          {
            "description": "Websearch query (plain words, quoted phrases, `OR`, `-`\nexclusions — Postgres websearch syntax).",
            "in": "query",
            "name": "q",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "format": "int64",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "format": "int64",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/PortalKbSearchHit"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          },
          "422": {
            "description": "empty query"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/portal/kb/search — FTS over client-visible published\narticles only (websearch query + trigram fallback, ranked the same\nway the unified search ranks).",
        "tags": [
          "portal"
        ]
      }
    },
    "/api/v1/portal/login": {
      "post": {
        "operationId": "portal_login",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PortalLoginRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortalLoginResponse"
                }
              }
            },
            "description": ""
          },
          "401": {
            "description": "bad credentials"
          }
        },
        "summary": "POST /api/portal/login — argon2 verify against `portal_users`. No MFA in\nportal v1 (documented deferral). Disabled accounts resolve to nothing →\nuniform 401, never revealing which half failed.",
        "tags": [
          "portal"
        ]
      }
    },
    "/api/v1/portal/me": {
      "get": {
        "operationId": "portal_me",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortalProfile"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/portal/me — the signed-in portal identity.",
        "tags": [
          "portal"
        ]
      }
    },
    "/api/v1/portal/refresh": {
      "post": {
        "operationId": "portal_refresh",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PortalRefreshRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortalLoginResponse"
                }
              }
            },
            "description": ""
          }
        },
        "summary": "POST /api/portal/refresh — rotation within the portal session family.\nA presented token resolves ONLY via its live session row; rotation\nrevokes that row, so replaying an old refresh token fails.",
        "tags": [
          "portal"
        ]
      }
    },
    "/api/v1/portal/schedule/slots": {
      "get": {
        "operationId": "portal_schedule_slots",
        "parameters": [
          {
            "description": "Range start (inclusive), ISO date.",
            "in": "query",
            "name": "from",
            "required": true,
            "schema": {
              "format": "date",
              "type": "string"
            }
          },
          {
            "description": "Range end (inclusive), ISO date.",
            "in": "query",
            "name": "to",
            "required": true,
            "schema": {
              "format": "date",
              "type": "string"
            }
          },
          {
            "description": "Optional: narrow to one staff member.",
            "in": "query",
            "name": "user_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/PortalStaffSlots"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          },
          "422": {
            "description": "range exceeds 31 days"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/portal/schedule/slots — published availability as FREE\nintervals per staff member: weekly windows minus time-off minus\nalready-booked time (appointments + on-call). Slots that already\nstarted are dropped; anything shorter than 30 minutes is noise.",
        "tags": [
          "portal"
        ]
      }
    },
    "/api/v1/portal/tickets": {
      "get": {
        "operationId": "portal_list_tickets",
        "parameters": [
          {
            "in": "query",
            "name": "board_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "in": "query",
            "name": "category",
            "required": false,
            "schema": {
              "oneOf": [
                {
                  "type": "null"
                },
                {
                  "$ref": "#/components/schemas/TicketStatusCategory"
                }
              ]
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "format": "int64",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "format": "int64",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/Ticket"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/portal/tickets — the caller's client's tickets across EXPOSED\nboards only. Unexposed boards are invisible, not empty-filtered.",
        "tags": [
          "portal"
        ]
      }
    },
    "/api/v1/portal/tickets/{id}": {
      "get": {
        "operationId": "portal_get_ticket",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortalTicketDetail"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/portal/tickets/{id} — detail plus comments through the\nnotes-taxonomy whitelist for the caller's tier. A ticket from another\nclient (or an unexposed board) is a 404, indistinguishable from absent.",
        "tags": [
          "portal"
        ]
      }
    },
    "/api/v1/portal/tickets/{id}/attachments": {
      "get": {
        "operationId": "portal_list_attachments",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/PortalAttachmentView"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/portal/tickets/{id}/attachments — attachments the portal\ncaller may see: ticket-level files always; comment files only when the\nowning note kind is visible to this tier.",
        "tags": [
          "portal"
        ]
      }
    },
    "/api/v1/portal/tickets/{id}/attachments/{attachment_id}/download": {
      "get": {
        "operationId": "portal_download_attachment",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "attachment_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/octet-stream": {
                "schema": {
                  "items": {
                    "format": "int32",
                    "minimum": 0,
                    "type": "integer"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/portal/tickets/{id}/attachments/{attachment_id}/download —\nstreams one visible attachment through the API. Hidden or foreign\nattachments are plain 404s (no existence leak).",
        "tags": [
          "portal"
        ]
      }
    },
    "/api/v1/portal/tickets/{id}/reply": {
      "post": {
        "operationId": "portal_reply",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PortalReplyRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TicketComment"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/portal/tickets/{id}/reply — ALWAYS creates a `client_visible`\ncomment regardless of tier, authored under portal audit provenance\n(`actor_kind = portal_contact | portal_approver | portal_it_manager`;\n`author_id` stays NULL because portal identities are not staff rows).\nEmits the SAME `ticket.comment_added` event as staff replies so every\ndownstream notification path works unchanged.",
        "tags": [
          "portal"
        ]
      }
    },
    "/api/v1/project-templates": {
      "get": {
        "operationId": "project_templates_list",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/ProjectTemplate"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/project-templates",
        "tags": [
          "projects"
        ]
      },
      "post": {
        "operationId": "project_templates_create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTemplateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TemplateMutationResponse"
                }
              }
            },
            "description": ""
          },
          "409": {
            "description": "template name already in use"
          },
          "422": {
            "description": "invalid template spec"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/project-templates — stores a blueprint (spec validated);\nemits `project.template_updated`.",
        "tags": [
          "projects"
        ]
      }
    },
    "/api/v1/project-templates/{id}": {
      "delete": {
        "operationId": "project_templates_delete",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          },
          "404": {
            "description": "template not visible in scope (rls_sparse)"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "DELETE /api/project-templates/{id} — blueprints are data, not live\nreferences: projects already instantiated are untouched; emits\n`project.template_removed`.",
        "tags": [
          "projects"
        ]
      },
      "patch": {
        "operationId": "project_templates_patch",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchTemplateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TemplateMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "template not visible in scope (rls_sparse)"
          },
          "422": {
            "description": "invalid template spec"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PATCH /api/project-templates/{id} — emits `project.template_updated`.",
        "tags": [
          "projects"
        ]
      }
    },
    "/api/v1/project-templates/{id}/instantiate": {
      "post": {
        "operationId": "project_templates_instantiate",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InstantiateTemplateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectInstantiateResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "template not visible in scope (rls_sparse)"
          },
          "409": {
            "description": "version conflict or idempotency key reused"
          },
          "422": {
            "description": "invalid template spec or request"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/project-templates/{id}/instantiate — expands the template\ninto a REAL project: phases, tasks, dependencies, and every lifecycle\nevent, all in ONE transaction (claim → expand → insert → events →\nrecord). Rollback on any failure leaves zero partial rows.",
        "tags": [
          "projects"
        ]
      }
    },
    "/api/v1/project-views": {
      "get": {
        "operationId": "project_views_list",
        "parameters": [
          {
            "description": "Scope to one project's views; omit for the org's ENTIRE view set.",
            "in": "query",
            "name": "project_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/ProjectView"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/project-views — one project's views, or all org views when\n`project_id` is omitted.",
        "tags": [
          "projects"
        ]
      },
      "post": {
        "operationId": "project_views_create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateViewRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ViewMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "project not visible in scope (rls_sparse)"
          },
          "409": {
            "description": "view name already in use in the scope"
          },
          "422": {
            "description": "validation failed"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/project-views — saves a view; emits `project.view_updated`.",
        "tags": [
          "projects"
        ]
      }
    },
    "/api/v1/project-views/{id}": {
      "delete": {
        "operationId": "project_views_delete",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          },
          "404": {
            "description": "view not visible in scope (rls_sparse)"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "DELETE /api/project-views/{id} — emits `project.view_removed`.",
        "tags": [
          "projects"
        ]
      },
      "patch": {
        "operationId": "project_views_patch",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchViewRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ViewMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "view not visible in scope (rls_sparse)"
          },
          "422": {
            "description": "validation failed"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PATCH /api/project-views/{id} — renames / respecs a view; emits\n`project.view_updated`.",
        "tags": [
          "projects"
        ]
      }
    },
    "/api/v1/projects": {
      "get": {
        "operationId": "projects_list",
        "parameters": [
          {
            "in": "query",
            "name": "status",
            "required": false,
            "schema": {
              "oneOf": [
                {
                  "type": "null"
                },
                {
                  "$ref": "#/components/schemas/ProjectStatus"
                }
              ]
            }
          },
          {
            "in": "query",
            "name": "client_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "format": "int64",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "format": "int64",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/Project"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/projects — filtered, newest-first list.",
        "tags": [
          "projects"
        ]
      },
      "post": {
        "operationId": "projects_create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateProjectRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectMutationResponse"
                }
              }
            },
            "description": ""
          },
          "409": {
            "description": "version conflict or idempotency key reused"
          },
          "422": {
            "description": "validation failed"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/projects — creates the project and emits `project.created` in\none transaction. Instant-first (IF1/IF2): idempotency-keyed,\nversion-gated, read-your-write response.",
        "tags": [
          "projects"
        ]
      }
    },
    "/api/v1/projects/{id}": {
      "get": {
        "operationId": "projects_get_one",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Project"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "not found"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/projects/{id}",
        "tags": [
          "projects"
        ]
      },
      "patch": {
        "operationId": "projects_patch",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchProjectRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "project not visible in scope (rls_sparse)"
          },
          "409": {
            "description": "version conflict or idempotency key reused"
          },
          "422": {
            "description": "validation failed"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PATCH /api/projects/{id} — tri-state partial update. Instant-first\n(IF1/IF2): idempotency-keyed, version-gated, returns prior + new values.",
        "tags": [
          "projects"
        ]
      }
    },
    "/api/v1/projects/{id}/phases": {
      "get": {
        "operationId": "projects_list_phases",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/ProjectPhase"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/projects/{id}/phases — ordered by sort_order.",
        "tags": [
          "projects"
        ]
      },
      "post": {
        "operationId": "projects_create_phase",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePhaseRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhaseMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "project not visible in scope (rls_sparse)"
          },
          "409": {
            "description": "version conflict or idempotency key reused"
          },
          "422": {
            "description": "validation failed"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/projects/{id}/phases — adds a phase; emits\n`project.phase_created`.",
        "tags": [
          "projects"
        ]
      }
    },
    "/api/v1/projects/{id}/phases/{phase_id}": {
      "patch": {
        "operationId": "projects_patch_phase",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "phase_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchPhaseRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhaseMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "phase not visible in scope (rls_sparse)"
          },
          "409": {
            "description": "version conflict or idempotency key reused"
          },
          "422": {
            "description": "validation failed"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PATCH /api/projects/{id}/phases/{phase_id} — tri-state partial update.",
        "tags": [
          "projects"
        ]
      }
    },
    "/api/v1/projects/{id}/phases/{phase_id}/complete": {
      "post": {
        "operationId": "projects_complete_phase",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "phase_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MutationParams"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhaseMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "phase not visible in scope (rls_sparse)"
          },
          "409": {
            "description": "already completed, version conflict, or idempotency key reused"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/projects/{id}/phases/{phase_id}/complete — stamps the phase\ncompleted and, when it is a billing milestone, emits\n`project.milestone_completed` in the same transaction (the core-billing\nseam). Instant-first: the idempotency key guarantees a retried\ncompletion can never double-emit the billing event.",
        "tags": [
          "projects"
        ]
      }
    },
    "/api/v1/projects/{id}/tasks": {
      "get": {
        "operationId": "projects_list_tasks",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "phase_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "in": "query",
            "name": "status",
            "required": false,
            "schema": {
              "oneOf": [
                {
                  "type": "null"
                },
                {
                  "$ref": "#/components/schemas/TaskStatus"
                }
              ]
            }
          },
          {
            "in": "query",
            "name": "assignee_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "in": "query",
            "name": "milestone",
            "required": false,
            "schema": {
              "type": [
                "boolean",
                "null"
              ]
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "format": "int64",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "format": "int64",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/ProjectTask"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/projects/{id}/tasks — filtered by phase/status/assignee and\nthe milestone flag, sort_order-ordered.",
        "tags": [
          "projects"
        ]
      },
      "post": {
        "operationId": "projects_create_task",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTaskRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "project not visible in scope (rls_sparse)"
          },
          "409": {
            "description": "version conflict or idempotency key reused"
          },
          "422": {
            "description": "validation failed"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/projects/{id}/tasks — creates the task (optionally with its\ndependency set) and emits `project.task_created` in one transaction.",
        "tags": [
          "projects"
        ]
      }
    },
    "/api/v1/projects/{id}/tasks/{task_id}": {
      "patch": {
        "operationId": "projects_patch_task",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "task_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchTaskRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "task not visible in scope (rls_sparse)"
          },
          "409": {
            "description": "version conflict or idempotency key reused"
          },
          "422": {
            "description": "validation failed"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PATCH /api/projects/{id}/tasks/{task_id} — tri-state partial update.\n`status: \"completed\"` is rejected: completion runs through the complete\nendpoint (dependency gating + the billing seam).",
        "tags": [
          "projects"
        ]
      }
    },
    "/api/v1/projects/{id}/tasks/{task_id}/complete": {
      "post": {
        "operationId": "projects_complete_task",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "task_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MutationParams"
              }
            }
          }
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "task not visible in scope (rls_sparse)"
          },
          "409": {
            "description": "dependencies unsatisfied, already completed, version conflict, or idempotency key reused"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/projects/{id}/tasks/{task_id}/complete — the guarded\ncompletion: every finish-to-start dependency must already be completed\n(typed 409 `task_dependencies_unsatisfied` naming the blockers), then\n`project.task_completed` fires — plus `project.milestone_completed`\nwhen the task is a billing milestone. Instant-first: the idempotency\nkey makes retried completions replay instead of double-billing.",
        "tags": [
          "projects"
        ]
      }
    },
    "/api/v1/projects/{id}/tasks/{task_id}/dependencies": {
      "get": {
        "operationId": "projects_get_dependencies",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "task_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DependencyListResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "not found"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/projects/{id}/tasks/{task_id}/dependencies",
        "tags": [
          "projects"
        ]
      },
      "put": {
        "operationId": "projects_set_dependencies",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "task_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetDependenciesRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DependencyListResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "task not visible in scope (rls_sparse)"
          },
          "422": {
            "description": "dependency set rejected (self-dep, cross-project, or cycle)"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PUT /api/projects/{id}/tasks/{task_id}/dependencies — replaces the\nwhole dependency set, cycle-checked over the project graph BEFORE any\nwrite; emits `project.task_updated`.",
        "tags": [
          "projects"
        ]
      }
    },
    "/api/v1/provenance": {
      "get": {
        "operationId": "provenance_list",
        "parameters": [
          {
            "description": "Keyset cursor from a previous page's `next_cursor`.",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Actor-kind filter (the write-trail vocabulary: human, agent,\nimport, ...).",
            "in": "query",
            "name": "actor_kind",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "The \"who\" filter: a user uuid. Ignored (forced to the caller) for\ncallers without the audit permission.",
            "in": "query",
            "name": "actor",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Entity family, e.g. \"ticket\". Required by `entity_id` and `field`.",
            "in": "query",
            "name": "entity",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Record id; requires `entity`.",
            "in": "query",
            "name": "entity_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Single-field provenance; requires `entity`.",
            "in": "query",
            "name": "field",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Agent session filter (rows carry it when present).",
            "in": "query",
            "name": "session_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Agent skill filter (rows carry it when present).",
            "in": "query",
            "name": "skill",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Rule-set hash filter (rows carry it when present).",
            "in": "query",
            "name": "ruleset_hash",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Restrict to undo reverts (`true`) or exclude them (`false`).",
            "in": "query",
            "name": "undo",
            "required": false,
            "schema": {
              "type": [
                "boolean",
                "null"
              ]
            }
          },
          {
            "description": "Inclusive lower bound on occurred_at.",
            "in": "query",
            "name": "from",
            "required": false,
            "schema": {
              "format": "date-time",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Inclusive upper bound on occurred_at.",
            "in": "query",
            "name": "to",
            "required": false,
            "schema": {
              "format": "date-time",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "format": "int64",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProvenancePage"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/provenance — the provenance read model: who / record+field /\nbefore-after / actor kind / agent session+skill+rule-set hash / when,\nnewest first, filterable, cursor-paged. Extends the 2.3 audit-log\nquery API with provenance-grade filters backed by the materialized\nprojection (no raw-row scans).",
        "tags": [
          "audit"
        ]
      }
    },
    "/api/v1/report-definitions": {
      "get": {
        "operationId": "report_definitions_list",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReportDefinitionList"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/report-definitions — visible definitions, deterministically\nordered `(name, id)`.",
        "tags": [
          "reports"
        ]
      },
      "post": {
        "operationId": "report_definitions_create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateReportDefinitionRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReportDefinitionMutationResponse"
                }
              }
            },
            "description": ""
          },
          "403": {
            "description": "missing reporting:create"
          },
          "409": {
            "description": "name conflict or idempotency key reused"
          },
          "422": {
            "description": "spec failed registry validation"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/report-definitions — create a stored definition through the\ninstant-first write path (idempotency key honored; response carries\n`mutation` metadata).",
        "tags": [
          "reports"
        ]
      }
    },
    "/api/v1/report-definitions/{id}": {
      "delete": {
        "operationId": "report_definitions_delete",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReportDefinitionMutationResponse"
                }
              }
            },
            "description": ""
          },
          "403": {
            "description": "definition outside the caller's writable scope"
          },
          "404": {
            "description": "rls_sparse: target not visible"
          },
          "409": {
            "description": "version conflict"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "DELETE /api/report-definitions/{id} — removal through the same gated\npath; the write trail keeps the deleted snapshot (undo substrate).",
        "tags": [
          "reports"
        ]
      },
      "get": {
        "operationId": "report_definitions_get",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReportDefinitionView"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "not visible in scope"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/report-definitions/{id} — one visible definition; anything not\nvisible (deleted, other org, private of another user) is a bare 404.",
        "tags": [
          "reports"
        ]
      },
      "put": {
        "operationId": "report_definitions_update",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateReportDefinitionRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReportDefinitionMutationResponse"
                }
              }
            },
            "description": ""
          },
          "403": {
            "description": "definition outside the caller's writable scope"
          },
          "404": {
            "description": "rls_sparse: target not visible"
          },
          "409": {
            "description": "version conflict or idempotency key reused"
          },
          "422": {
            "description": "spec failed registry validation"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PUT /api/report-definitions/{id} — full-replace update through the\ninstant-first write path (version gate enforced; a miss inside a\nmutation is the typed `rls_sparse` reason, not `not_found`).",
        "tags": [
          "reports"
        ]
      }
    },
    "/api/v1/report-schedules": {
      "get": {
        "operationId": "report_schedules_list",
        "parameters": [
          {
            "description": "Opaque keyset cursor from a previous page's `next_cursor`.",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Page size, clamped to [1, 200].",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "format": "int64",
              "type": [
                "integer",
                "null"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReportSchedulePage"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/report-schedules — cursor-paged listing (admin), ordered\n`(name, id)`, each row carrying its next-run preview.",
        "tags": [
          "reports"
        ]
      },
      "post": {
        "operationId": "report_schedules_create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateReportScheduleRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReportScheduleMutationResponse"
                }
              }
            },
            "description": ""
          },
          "403": {
            "description": "admin-only surface"
          },
          "409": {
            "description": "name conflict or idempotency key reused"
          },
          "422": {
            "description": "validation failed (shape, recipients, definition)"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/report-schedules — create a schedule through the\ninstant-first write path; the next-run preview computes from now.",
        "tags": [
          "reports"
        ]
      }
    },
    "/api/v1/report-schedules/{id}": {
      "delete": {
        "operationId": "report_schedules_delete",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReportScheduleMutationResponse"
                }
              }
            },
            "description": ""
          },
          "403": {
            "description": "admin-only surface"
          },
          "404": {
            "description": "rls_sparse: target not visible"
          },
          "409": {
            "description": "version conflict"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "DELETE /api/report-schedules/{id} — removal through the same gated\npath; ledger rows cascade and the write trail keeps the snapshot.",
        "tags": [
          "reports"
        ]
      },
      "get": {
        "operationId": "report_schedules_get",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReportScheduleView"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "not in scope"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/report-schedules/{id} — one schedule; anything not in this\norg is a bare 404.",
        "tags": [
          "reports"
        ]
      },
      "put": {
        "operationId": "report_schedules_update",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateReportScheduleRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReportScheduleMutationResponse"
                }
              }
            },
            "description": ""
          },
          "403": {
            "description": "admin-only surface"
          },
          "404": {
            "description": "rls_sparse: target not visible"
          },
          "409": {
            "description": "name conflict or version conflict"
          },
          "422": {
            "description": "validation failed"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PUT /api/report-schedules/{id} — full-replace update; the next-run\npreview recomputes from now (cadence changes cannot strand a slot in\nthe past; the worker's claim sweep catches up enabled schedules\nanyway, so this only affects the preview's freshness).",
        "tags": [
          "reports"
        ]
      }
    },
    "/api/v1/reports/{kind}": {
      "get": {
        "operationId": "report_get",
        "parameters": [
          {
            "description": "Inclusive window start (UTC day, YYYY-MM-DD). Default: 30 trailing days.",
            "in": "query",
            "name": "from",
            "required": false,
            "schema": {
              "format": "date",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Inclusive window end (UTC day). Max span with `from`: 366 days.",
            "in": "query",
            "name": "to",
            "required": false,
            "schema": {
              "format": "date",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Opaque keyset cursor from a previous page's `next_cursor`.",
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Page size, clamped to [1, 500].",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "format": "int64",
              "type": "integer"
            }
          },
          {
            "description": "`\"csv\"` streams text/csv instead of the JSON envelope.",
            "in": "query",
            "name": "format",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Manager-only narrowing onto one staff member; non-managers are\nALWAYS forced onto themselves regardless of this parameter.",
            "in": "query",
            "name": "user_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "SLA kinds: restrict to one governing policy.",
            "in": "query",
            "name": "policy_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Time rollups: filter billable/non-billable entries.",
            "in": "query",
            "name": "billable",
            "required": false,
            "schema": {
              "type": [
                "boolean",
                "null"
              ]
            }
          },
          {
            "description": "ticket_aging only: snapshot instant for ages (default: now).",
            "in": "query",
            "name": "as_of",
            "required": false,
            "schema": {
              "format": "date-time",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "in": "path",
            "name": "kind",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReportPage"
                }
              }
            },
            "description": "Report page (JSON envelope or CSV stream)"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/reports/{kind} — prebuilt operational report over the read-model\nviews. Kinds: time_by_user | time_by_client | time_by_ticket |\nsla_attainment | sla_breaches | ticket_throughput | ticket_aging |\nfirst_response.",
        "tags": [
          "reports"
        ]
      }
    },
    "/api/v1/scheduling/conflict-check": {
      "post": {
        "operationId": "scheduling_conflict_check",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConflictCheckRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ConflictCheckResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/scheduling/conflict-check — dry-run overlap probe that writes\nnothing: returns every blocking booking for the candidate slot.",
        "tags": [
          "scheduling"
        ]
      }
    },
    "/api/v1/search": {
      "get": {
        "operationId": "search_query",
        "parameters": [
          {
            "description": "Free-text query using websearch syntax: `\"exact phrases\"`,\n`-excluded`, plain terms AND-ed. Tokens ≥3 chars also match as\nsubstrings via the trigram fallback.",
            "in": "query",
            "name": "q",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "format": "int64",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "format": "int64",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SearchResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/search — unified staff search across tickets, comments and the\nclient hierarchy.",
        "tags": [
          "search"
        ]
      }
    },
    "/api/v1/settings/ai/byok": {
      "put": {
        "operationId": "settings_ai_byok_put",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PutByokSecretRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ByokSecretMutationResponse"
                }
              }
            },
            "description": ""
          },
          "403": {
            "description": ""
          },
          "409": {
            "description": "idempotency key reused or version conflict"
          },
          "422": {
            "description": "invalid provider or key"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PUT /api/settings/ai/byok — seals and stores an API key at rest\n(Admin:edit + owner/admin standing). Rides the instant-first write\npath; replays are byte-identical and the trail stores presence flags\nonly.",
        "tags": [
          "settings"
        ]
      }
    },
    "/api/v1/settings/ai/byok/{provider}": {
      "delete": {
        "operationId": "settings_ai_byok_delete",
        "parameters": [
          {
            "in": "path",
            "name": "provider",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ByokSecretMutationResponse"
                }
              }
            },
            "description": ""
          },
          "403": {
            "description": ""
          },
          "404": {
            "description": "rls_sparse: no key stored for that provider"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "DELETE /api/settings/ai/byok/{provider} — removes a sealed BYOK key\nthrough the same gated path; the write trail keeps the presence\nsnapshot.",
        "tags": [
          "settings"
        ]
      }
    },
    "/api/v1/settings/ai/status": {
      "get": {
        "operationId": "settings_ai_status",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ByokOverviewResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/settings/ai/status — overview of AI completion provider & configured keys.",
        "tags": [
          "settings"
        ]
      }
    },
    "/api/v1/settings/ai/test": {
      "post": {
        "operationId": "settings_ai_test",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TestConnectionRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TestConnectionResponse"
                }
              }
            },
            "description": ""
          },
          "403": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/settings/ai/test — test-connection probe (Admin:edit gated).\nNone mode returns the typed unavailable outcome; a configured provider\nverifies its sealed key still decrypts (tamper/rotation check). No\nvendor HTTP call happens in v1 — the live probe rides the edge adapters\nwhen a lane wires them.",
        "tags": [
          "settings"
        ]
      }
    },
    "/api/v1/settings/org": {
      "get": {
        "operationId": "settings_org_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/ValueView"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/settings/org — effective org settings (defaults overlaid by\nstored overrides). Visible to every member.",
        "tags": [
          "settings"
        ]
      },
      "put": {
        "operationId": "settings_org_put",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateSettingRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValueView"
                }
              }
            },
            "description": ""
          },
          "403": {
            "description": ""
          },
          "422": {
            "description": "unknown key or invalid value"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PUT /api/settings/org — upserts one org-scope override after registry\nvalidation (Admin:edit required). Emits `setting.updated` + audit row.",
        "tags": [
          "settings"
        ]
      }
    },
    "/api/v1/settings/registry": {
      "get": {
        "operationId": "settings_registry",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/settings/registry — every declared setting with kind, default,\nscope and validation shape. Any authenticated member may read it.",
        "tags": [
          "settings"
        ]
      }
    },
    "/api/v1/settings/user": {
      "get": {
        "operationId": "settings_user_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/ValueView"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/settings/user — the caller's effective personal settings.",
        "tags": [
          "settings"
        ]
      },
      "put": {
        "operationId": "settings_user_put",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateSettingRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValueView"
                }
              }
            },
            "description": ""
          },
          "422": {
            "description": "unknown key or invalid value"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PUT /api/settings/user — upserts one of the CALLER's own user-scope\noverrides. No role requirement: everyone may tune their own preferences.",
        "tags": [
          "settings"
        ]
      }
    },
    "/api/v1/sla/calendars": {
      "get": {
        "operationId": "sla_calendars_list",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/SlaCalendar"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/sla/calendars",
        "tags": [
          "sla"
        ]
      },
      "post": {
        "operationId": "sla_calendars_create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCalendarRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SlaCalendar"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/sla/calendars",
        "tags": [
          "sla"
        ]
      }
    },
    "/api/v1/sla/calendars/{id}": {
      "delete": {
        "operationId": "sla_calendars_delete",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "DELETE /api/sla/calendars/{id} — detaches policies (FK SET NULL); their\nembedded calendars keep governing.",
        "tags": [
          "sla"
        ]
      },
      "patch": {
        "operationId": "sla_calendars_update",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCalendarRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SlaCalendar"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PATCH /api/sla/calendars/{id} — partial update; validates the merged\nresult by re-reading and running domain validation.",
        "tags": [
          "sla"
        ]
      }
    },
    "/api/v1/sla/policies": {
      "get": {
        "operationId": "sla_policies_list",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/PolicyView"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/sla/policies",
        "tags": [
          "sla"
        ]
      }
    },
    "/api/v1/sla/policies/{id}/ladder": {
      "get": {
        "operationId": "sla_ladder_get",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/EscalationStep"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/sla/policies/{id}/ladder — enabled + disabled steps, ordered.",
        "tags": [
          "sla"
        ]
      },
      "put": {
        "operationId": "sla_ladder_replace",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReplaceLadderRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/EscalationStep"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PUT /api/sla/policies/{id}/ladder — replaces the whole ladder in one tx.",
        "tags": [
          "sla"
        ]
      }
    },
    "/api/v1/sso/exchange": {
      "post": {
        "operationId": "sso_exchange",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SsoExchangeRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SsoExchangeResponse"
                }
              }
            },
            "description": ""
          },
          "401": {
            "description": ""
          }
        },
        "summary": "POST /api/auth/sso/exchange — swaps the single-use callback code for\ntokens (or a link confirmation). Codes die on first use or after 60s.",
        "tags": [
          "auth"
        ]
      }
    },
    "/api/v1/tickets": {
      "get": {
        "operationId": "tickets_list",
        "parameters": [
          {
            "in": "query",
            "name": "board_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "in": "query",
            "name": "assignee_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "in": "query",
            "name": "client_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "in": "query",
            "name": "category",
            "required": false,
            "schema": {
              "oneOf": [
                {
                  "type": "null"
                },
                {
                  "$ref": "#/components/schemas/TicketStatusCategory"
                }
              ]
            }
          },
          {
            "in": "query",
            "name": "priority",
            "required": false,
            "schema": {
              "oneOf": [
                {
                  "type": "null"
                },
                {
                  "$ref": "#/components/schemas/Priority"
                }
              ]
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "format": "int64",
              "type": "integer"
            }
          },
          {
            "in": "query",
            "name": "offset",
            "required": false,
            "schema": {
              "format": "int64",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/TicketWithFields"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/tickets — filtered, priority-ordered list; each row carries its\ncustom-field values (TASKLIST 2.17) fetched in one batched query.",
        "tags": [
          "tickets"
        ]
      },
      "post": {
        "operationId": "tickets_create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTicketRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TicketMutationResponse"
                }
              }
            },
            "description": ""
          },
          "409": {
            "description": "version conflict or idempotency key reused"
          },
          "422": {
            "description": "missing required custom fields or invalid value"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/tickets — allocates the human ticket number, initializes SLA\nclocks, validates + stores any initial custom-field values (REQUIRED\ndefinitions enforced), and emits `ticket.created` — all in one transaction.\nInstant-first (IF1/IF2): routed through the shared idempotency gate and\nreturns the read-your-write `mutation` metadata.",
        "tags": [
          "tickets"
        ]
      }
    },
    "/api/v1/tickets/my-work": {
      "get": {
        "operationId": "tickets_my_work",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/MyWorkItem"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/tickets/my-work — everything assigned to me, not closed,\nacross all boards, priority-then-SLA-due ordered (the unified\ncross-board view from §1; TASKLIST 2.11 adds client/board annotations).",
        "tags": [
          "tickets"
        ]
      }
    },
    "/api/v1/tickets/{id}": {
      "get": {
        "operationId": "tickets_get_one",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TicketWithFields"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/tickets/{id}",
        "tags": [
          "tickets"
        ]
      },
      "patch": {
        "operationId": "tickets_patch",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PatchTicketRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TicketMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "ticket not visible in scope (rls_sparse)"
          },
          "409": {
            "description": "version conflict or idempotency key reused"
          },
          "422": {
            "description": "invalid custom-field value"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PATCH /api/tickets/{id} — partial update; validates + upserts any\nprovided custom-field values; emits `ticket.updated`,\n`ticket.field_set` (per changed field), and `ticket.assigned` when the\nassignee changes. Instant-first (IF1/IF2): idempotency-keyed, version-\ngated, and returns prior + new values for undo.",
        "tags": [
          "tickets"
        ]
      }
    },
    "/api/v1/tickets/{id}/attachments": {
      "get": {
        "operationId": "attachments_list_for_ticket",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/Attachment"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/tickets/{id}/attachments — every attachment on one ticket.",
        "tags": [
          "attachments"
        ]
      },
      "post": {
        "description": "Headers: `x-filename` (required), `content-type` (declared; verified\nagainst sniffed magic bytes). Body: raw bytes, capped by\n`MERIDIAN_MAX_UPLOAD_MB` (default 25 MB).",
        "operationId": "attachments_upload",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/octet-stream": {
              "schema": {
                "items": {
                  "format": "int32",
                  "minimum": 0,
                  "type": "integer"
                },
                "type": "array"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Attachment"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/tickets/{id}/attachments — stores one file against a ticket\n(linked to a comment later by the composer submit).",
        "tags": [
          "attachments"
        ]
      }
    },
    "/api/v1/tickets/{id}/checklist": {
      "get": {
        "operationId": "tickets_get_checklist",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TicketChecklistView"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/tickets/{id}/checklist — lazily instantiates any template items\nthe ticket has not picked up yet, then returns the full view.",
        "tags": [
          "tickets"
        ]
      },
      "post": {
        "operationId": "tickets_add_checklist_item",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddChecklistItemRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TicketChecklistMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "ticket not visible in scope (rls_sparse)"
          },
          "409": {
            "description": "idempotency key reused"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/tickets/{id}/checklist — appends an ad-hoc checklist item.\nAd-hoc items never block closure; emits `ticket.checklist_updated`.\nInstant-first (IF1/IF2): idempotency-keyed and returns the\nread-your-write mutation metadata for the created item.",
        "tags": [
          "tickets"
        ]
      }
    },
    "/api/v1/tickets/{id}/checklist/{item_id}": {
      "post": {
        "operationId": "tickets_set_checklist_item",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "item_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetChecklistItemRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TicketChecklistMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "ticket or item not visible in scope (rls_sparse)"
          },
          "409": {
            "description": "idempotency key reused"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/tickets/{id}/checklist/{item_id} — toggles one checklist item;\nemits `ticket.checklist_updated` in the same transaction. Instant-first\n(IF1/IF2): idempotency-keyed and returns the read-your-write mutation\nmetadata for the toggled item.",
        "tags": [
          "tickets"
        ]
      }
    },
    "/api/v1/tickets/{id}/comments": {
      "get": {
        "operationId": "tickets_list_comments",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "Optional taxonomy filter (`internal`, `client_visible`,\n`in_house_update`). Omit for all kinds (staff view).",
            "in": "query",
            "name": "kind",
            "required": false,
            "schema": {
              "oneOf": [
                {
                  "type": "null"
                },
                {
                  "$ref": "#/components/schemas/NoteKind"
                }
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/TicketComment"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/tickets/{id}/comments — internal notes require ticket view;\nthe portal surface filters kinds separately (portal v1).",
        "tags": [
          "tickets"
        ]
      },
      "post": {
        "operationId": "tickets_add_comment",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddCommentRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TicketCommentMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "ticket not visible in scope (rls_sparse)"
          },
          "409": {
            "description": "idempotency key reused"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/tickets/{id}/comments — adds a structured note; @mentions\nfan out into the notification center. Instant-first (IF1/IF2):\nidempotency-keyed and returns the read-your-write mutation metadata.",
        "tags": [
          "tickets"
        ]
      }
    },
    "/api/v1/tickets/{id}/comments/{comment_id}/attachments": {
      "get": {
        "operationId": "attachments_list_for_comment",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "comment_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/Attachment"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/tickets/{id}/comments/{comment_id}/attachments — one comment's\nattachments.",
        "tags": [
          "attachments"
        ]
      }
    },
    "/api/v1/tickets/{id}/fields/{field_id}": {
      "delete": {
        "operationId": "fields_clear_ticket_value",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "field_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": ""
          },
          "422": {
            "description": "field is required and cannot be emptied"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "DELETE /api/tickets/{id}/fields/{field_id} — clears one value; refuses\n(422) to empty a REQUIRED definition; emits `ticket.field_cleared`.",
        "tags": [
          "fields"
        ]
      },
      "put": {
        "operationId": "fields_set_ticket_value",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "in": "path",
            "name": "field_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetTicketFieldValueRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TicketCustomFieldValue"
                }
              }
            },
            "description": ""
          },
          "422": {
            "description": "value does not validate against the definition"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PUT /api/tickets/{id}/fields/{field_id} — validates the incoming JSON\nagainst the definition (kind coercion, option membership) and stores the\ncanonical encoding; emits `ticket.field_set`.",
        "tags": [
          "fields"
        ]
      }
    },
    "/api/v1/tickets/{id}/revert": {
      "post": {
        "operationId": "tickets_revert",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RevertTicketRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TicketRevertResponse"
                }
              }
            },
            "description": ""
          },
          "409": {
            "description": "version conflict, idempotency key reuse, or undo_reverts_only (closed record, whole-record revert)"
          },
          "422": {
            "description": "unknown target seq, non-restorable step/field, or nothing to restore"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/tickets/{id}/revert — undo one server-accepted edit by\nrestoring its prior values as a NORMAL authorized idempotent write\n(IF1 envelope end to end). Appends a new trail row (op `revert`),\nemits `ticket.reverted` on the event bus, and writes the audited\n`ticket.reverted` trail row — the append-only history is never\nrewritten.",
        "tags": [
          "tickets"
        ]
      }
    },
    "/api/v1/tickets/{id}/sla": {
      "get": {
        "operationId": "tickets_sla_status",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TicketSlaStatus"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/tickets/{id}/comments — optional kind filter; internal notes\nrequire ticket view. The portal surface must consume the dedicated\nclient-visible read (`core-db::tickets::list_client_visible_comments`),\nnever this staff endpoint.\nGET /api/tickets/{id}/sla — clock state plus a live business-time\nremaining estimate for the resolution budget (drives the UI badge).",
        "tags": [
          "tickets"
        ]
      }
    },
    "/api/v1/tickets/{id}/status": {
      "post": {
        "operationId": "tickets_change_status",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChangeStatusRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TicketStatusMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "ticket not visible in scope (rls_sparse)"
          },
          "409": {
            "description": "pre-close checklist blocked, version conflict, or idempotency key reused"
          },
          "422": {
            "description": "invalid transition"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/tickets/{id}/status — the guarded lifecycle transition:\ndomain transition rules, pre-close checklist enforcement (typed 409\nlisting the incomplete required items when the board enforces), SLA\npause bookkeeping, and the `ticket.status_changed` event, all in one tx.\nInstant-first (IF1/IF2): idempotency-keyed, version-gated, read-your-write.",
        "tags": [
          "tickets"
        ]
      }
    },
    "/api/v1/tickets/{id}/time-entries": {
      "get": {
        "operationId": "tickets_ticket_time_entries",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/TimeEntry"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/tickets/{id}/time-entries",
        "tags": [
          "tickets"
        ]
      }
    },
    "/api/v1/tickets/{id}/undo-stack": {
      "get": {
        "operationId": "tickets_undo_stack",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "Maximum steps / field rows returned (1–200, default 50). Newest\nfirst; the first step's `seq` is the record's current version.",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "format": "int64",
              "type": [
                "integer",
                "null"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UndoStackResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "ticket not visible in scope"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/tickets/{id}/undo-stack — the per-field / per-record\napplied-state history read model for one record.",
        "tags": [
          "tickets"
        ]
      }
    },
    "/api/v1/time-entries": {
      "get": {
        "operationId": "timers_list_entries",
        "parameters": [
          {
            "in": "query",
            "name": "ticket_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "in": "query",
            "name": "user_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "in": "query",
            "name": "since",
            "required": false,
            "schema": {
              "format": "date-time",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "format": "int64",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/TimeEntry"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/time-entries",
        "tags": [
          "timers"
        ]
      },
      "post": {
        "operationId": "timers_create_entry",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTimeEntryRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimeEntry"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/time-entries — manual entry (no timer).",
        "tags": [
          "timers"
        ]
      }
    },
    "/api/v1/time-gaps": {
      "get": {
        "operationId": "time_gaps_user",
        "parameters": [
          {
            "description": "Inclusive local-day start (YYYY-MM-DD). Defaults to yesterday.",
            "in": "query",
            "name": "from",
            "required": false,
            "schema": {
              "format": "date",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Inclusive local-day end (YYYY-MM-DD). Defaults to `from`.",
            "in": "query",
            "name": "to",
            "required": false,
            "schema": {
              "format": "date",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Manager report only: whose days. Requires owner/admin.",
            "in": "query",
            "name": "user_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GapReportResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/time-gaps?user_id= — manager-scoped report for one member.\nOwner/admin only; everyone else uses `/api/time-gaps/me`.",
        "tags": [
          "timers"
        ]
      }
    },
    "/api/v1/time-gaps/me": {
      "get": {
        "operationId": "time_gaps_me",
        "parameters": [
          {
            "description": "Inclusive local-day start (YYYY-MM-DD). Defaults to yesterday.",
            "in": "query",
            "name": "from",
            "required": false,
            "schema": {
              "format": "date",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Inclusive local-day end (YYYY-MM-DD). Defaults to `from`.",
            "in": "query",
            "name": "to",
            "required": false,
            "schema": {
              "format": "date",
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "description": "Manager report only: whose days. Requires owner/admin.",
            "in": "query",
            "name": "user_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": [
                "string",
                "null"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GapReportResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/time-gaps/me — the caller's day-level gap report (defaults to\nyesterday in the caller's timezone).",
        "tags": [
          "timers"
        ]
      }
    },
    "/api/v1/time-settings": {
      "get": {
        "operationId": "time_settings_get",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimeSettingsResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/time-settings — org time-discipline knobs (admin).",
        "tags": [
          "timers"
        ]
      },
      "put": {
        "operationId": "time_settings_put",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTimeSettingsRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimeSettingsResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PUT /api/time-settings — update the org's time-discipline knobs (admin).",
        "tags": [
          "timers"
        ]
      }
    },
    "/api/v1/timers/active": {
      "get": {
        "operationId": "timers_active",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/timers/active — the caller's running session (at most one).",
        "tags": [
          "timers"
        ]
      }
    },
    "/api/v1/timers/pause": {
      "post": {
        "operationId": "timers_pause",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PauseTimerRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimerSession"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/timers/pause — pauses the active (or given) session, recording\nthe reason on the segment.",
        "tags": [
          "timers"
        ]
      }
    },
    "/api/v1/timers/resume": {
      "post": {
        "operationId": "timers_resume",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PauseTimerRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimerSession"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/timers/resume — resumes a paused session with a new segment.",
        "tags": [
          "timers"
        ]
      }
    },
    "/api/v1/timers/start": {
      "post": {
        "operationId": "timers_start",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StartTimerRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimerMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "ticket not visible in scope (rls_sparse)"
          },
          "409": {
            "description": "idempotency key reused"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/timers/start — starts (or switches to) a timer. If another\nsession is running it is auto-paused with reason `switched` and stays in\nthe working set; the DB's partial unique index is the backstop.\nInstant-first (IF1/IF2): idempotency-keyed and read-your-write.",
        "tags": [
          "timers"
        ]
      }
    },
    "/api/v1/timers/stop": {
      "post": {
        "operationId": "timers_stop",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StopTimerRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TimeEntryMutationResponse"
                }
              }
            },
            "description": ""
          },
          "404": {
            "description": "session not visible in scope (rls_sparse)"
          },
          "409": {
            "description": "version conflict or idempotency key reused"
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/timers/stop — stops the session and materializes a time entry\n(rounded up to the minute) in the same transaction.",
        "tags": [
          "timers"
        ]
      }
    },
    "/api/v1/timers/working-set": {
      "get": {
        "operationId": "timers_working_set",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/TimerSession"
                  },
                  "type": "array"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/timers/working-set — recent sessions (running first): the\ndocked working set the UI renders.",
        "tags": [
          "timers"
        ]
      }
    },
    "/api/v1/webhooks": {
      "get": {
        "operationId": "webhooks_list",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookList"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/webhooks — the org's subscriptions (never includes secrets).",
        "tags": [
          "integrations"
        ]
      },
      "post": {
        "operationId": "webhooks_create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateWebhookRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookSecretResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/webhooks — create a subscription; responds with the signing\nsecret once. Emits an audit record in the same transaction.",
        "tags": [
          "integrations"
        ]
      }
    },
    "/api/v1/webhooks/{id}": {
      "delete": {
        "operationId": "webhooks_delete",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "DELETE /api/webhooks/{id} — removes the subscription; deliveries\ncascade (history is intentionally scoped to the subscription's life).",
        "tags": [
          "integrations"
        ]
      },
      "patch": {
        "operationId": "webhooks_update",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateWebhookRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookView"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "PATCH /api/webhooks/{id} — mutate URL / filter / enabled flag.",
        "tags": [
          "integrations"
        ]
      }
    },
    "/api/v1/webhooks/{id}/deliveries": {
      "get": {
        "operationId": "webhooks_deliveries_list",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "cursor",
            "required": false,
            "schema": {
              "type": [
                "string",
                "null"
              ]
            }
          },
          {
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "format": "int64",
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeliveryPage"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "GET /api/webhooks/{id}/deliveries — the in-app delivery log, newest\nfirst, keyset-cursor paged.",
        "tags": [
          "integrations"
        ]
      }
    },
    "/api/v1/webhooks/{id}/test": {
      "post": {
        "operationId": "webhooks_test_fire",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TestFireResponse"
                }
              }
            },
            "description": ""
          }
        },
        "security": [
          {
            "bearer": []
          }
        ],
        "summary": "POST /api/webhooks/{id}/test — fires one `webhook.test` envelope into\nthe real pipeline (outbox → relay → stream → signed delivery), then\nreturns 202; poll the deliveries endpoint to watch attempts land.",
        "tags": [
          "integrations"
        ]
      }
    }
  },
  "tags": [
    {
      "description": "Registration, login, token lifecycle",
      "name": "auth"
    },
    {
      "description": "Client → site → contact → asset hierarchy",
      "name": "clients"
    },
    {
      "description": "Boards and semantic-category-bound statuses",
      "name": "boards"
    },
    {
      "description": "Ticketing: lifecycle, notes, checklists",
      "name": "tickets"
    },
    {
      "description": "Single-active-timer workflow + time entries",
      "name": "timers"
    },
    {
      "description": "Notification center",
      "name": "notifications"
    },
    {
      "description": "Typed settings registry: org + user scoped values",
      "name": "settings"
    },
    {
      "description": "Append-only audit log with filters + cursor pagination (admin)",
      "name": "audit"
    },
    {
      "description": "Unified FTS search across tickets, comments and clients",
      "name": "search"
    },
    {
      "description": "Operational reports + stored report definitions over the versioned read-model views",
      "name": "reports"
    },
    {
      "description": "Append-only audit log (admin)",
      "name": "audit"
    },
    {
      "description": "SLA calendars, policies, escalation ladders (admin)",
      "name": "sla"
    },
    {
      "description": "Event-triggered automation rules (admin)",
      "name": "automations"
    },
    {
      "description": "Client portal v1: login, own-client tickets, replies",
      "name": "portal"
    },
    {
      "description": "Staff administration of portal users + board exposure",
      "name": "portal-admin"
    },
    {
      "description": "Signed webhooks OUT + scoped API keys (plugin runtime v1)",
      "name": "integrations"
    },
    {
      "description": "Contracts (recurring / T&M / retainer / fixed-fee) + billing-rule previews + native invoicing v1: invoice runs, payments (PaymentProvider seam, none-mode), dunning states",
      "name": "billing"
    },
    {
      "description": "Appointments, availability, on-call, calendar views",
      "name": "scheduling"
    },
    {
      "description": "Projects: phases/tasks/dependencies/views/templates + milestone billing events",
      "name": "projects"
    },
    {
      "description": "File attachments on tickets/comments (ObjectStore-backed)",
      "name": "attachments"
    },
    {
      "description": "Native knowledge base: categories, articles, client-facing flags",
      "name": "kb"
    },
    {
      "description": "Documents with immutable, append-only, diffable versions (restore-creates-new-version)",
      "name": "documents"
    },
    {
      "description": "Alert ingestor: HMAC-signed webhook ingest, dedup/correlation, storm collapse into incident tickets",
      "name": "alerts"
    },
    {
      "description": "Dispatch connector v1: scoped machine surface — schedule reads + field-service status pushes (API-key dispatch:read / dispatch:write)",
      "name": "dispatch-connector"
    },
    {
      "description": "Agent platform v1: capability registry (deny-by-default, involvement dial), versioned agent skills, IF8 proposal pipeline (approval by default)",
      "name": "agent-platform"
    },
    {
      "description": "Migration connector (third-party tools): bulk push riding the import engine with checkpoint cursors, cursor-paged read-model pull; API-key scoped (migration:read/write), per-key rate limited",
      "name": "migration"
    }
  ]
}
